From acb8bd8c58cb80bff83a0f25040e7ae91a25cabd Mon Sep 17 00:00:00 2001 From: yanglbme Date: Wed, 28 Nov 2018 21:23:30 +0800 Subject: [PATCH] docs(dubbo): add dubbo-service-management.md --- README.md | 2 +- .../dubbo-service-management.md | 117 ++++++++++++++++++ img/dubbo-service-invoke-road.png | Bin 0 -> 14658 bytes 3 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 docs/distributed-system/dubbo-service-management.md create mode 100644 img/dubbo-service-invoke-road.png diff --git a/README.md b/README.md index 65191ca..a501d55 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ - [Dubbo 支持哪些序列化协议?说一下 Hessian 的数据结构?PB 知道吗?为什么 PB 的效率是最高的?](/docs/distributed-system/dubbo-serialization-protocol.md) - [Dubbo 负载均衡策略和集群容错策略都有哪些?动态代理策略呢?](/docs/distributed-system/dubbo-load-balancing.md) - [Dubbo 的 spi 思想是什么?](/docs/distributed-system/dubbo-spi.md) -- 如何基于 Dubbo 进行服务治理、服务降级、失败重试以及超时重试? +- [如何基于 Dubbo 进行服务治理、服务降级、失败重试以及超时重试?](/docs/distributed-system/dubbo-service-management.md) - 分布式服务接口的幂等性如何设计(比如不能重复扣款)? - 分布式服务接口请求的顺序性如何保证? - 如何自己设计一个类似 Dubbo 的 rpc 框架? diff --git a/docs/distributed-system/dubbo-service-management.md b/docs/distributed-system/dubbo-service-management.md new file mode 100644 index 0000000..d3a5708 --- /dev/null +++ b/docs/distributed-system/dubbo-service-management.md @@ -0,0 +1,117 @@ +## 面试题 +如何基于 dubbo 进行服务治理、服务降级、失败重试以及超时重试? + +## 面试官心理分析 +服务治理,这个问题如果问你,其实就是看看你有没有**服务治理**的思想,因为这个是做过复杂微服务的人肯定会遇到的一个问题。 + +**服务降级**,这个是涉及到复杂分布式系统中必备的一个话题,因为分布式系统互相来回调用,任何一个系统故障了,你不降级,直接就全盘崩溃?那就太坑爹了吧。 + +**失败重试**,分布式系统中网络请求如此频繁,要是因为网络问题不小心失败了一次,是不是要重试? + +**超时重试**,同上,如果不小心网络慢一点,超时了,如何重试? + +## 面试题剖析 +### 服务治理 +#### 1. 调用链路自动生成 +一个大型的分布式系统,或者说是用现在流行的微服务架构来说吧,**分布式系统由大量的服务组成**。那么这些服务之间互相是如何调用的?调用链路是啥?说实话,几乎到后面没人搞的清楚了,因为服务实在太多了,可能几百个甚至几千个服务。 + +那就需要基于 dubbo 做的分布式系统中,对各个服务之间的调用自动记录下来,然后自动将**各个服务之间的依赖关系和调用链路生成出来**,做成一张图,显示出来,大家才可以看到对吧。 + +![dubbo-service-invoke-road](/img/dubbo-service-invoke-road.png) + +#### 2. 服务访问压力以及时长统计 +需要自动统计**各个接口和服务之间的调用次数以及访问延时**,而且要分成两个级别。 + +- 一个级别是接口粒度,就是每个服务的每个接口每天被调用多少次,TP50/TP90/TP99,三个档次的请求延时分别是多少; +- 第二个级别是从源头入口开始,一个完整的请求链路经过几十个服务之后,完成一次请求,每天全链路走多少次,全链路请求延时的 TP50/TP90/TP99,分别是多少。 + +这些东西都搞定了之后,后面才可以来看当前系统的压力主要在哪里,如何来扩容和优化啊。 + +#### 3. 其它 +- 服务分层(避免循环依赖) +- 调用链路失败监控和报警 +- 服务鉴权 +- 每个服务的可用性的监控(接口调用成功率?几个9?99.99%,99.9%,99%。 + +### 服务降级 +比如说服务 A调用服务 B,结果服务 B 挂掉了,服务 A 重试几次调用服务 B,还是不行,那么直接降级,走一个备用的逻辑,给用户返回响应。 + +举个栗子,我们有接口 `HelloService`。`HelloServiceImpl` 有该接口的具体实现。 + +```java +public interface HelloService { + + void sayHello(); + +} + +public class HelloServiceImpl implements HelloService { + + public void sayHello() { + System.out.println("hello world......"); + } + +} + +``` + +```xml + + + + + + + + + + + + + + + + + + + + + + + +``` + +我们调用接口失败的时候,可以通过 `mock` 统一返回 null。 + +mock 的值也可以修改为 true,然后再跟接口同一个路径下实现一个 Mock 类,命名规则是 `接口名称+Mock` 后缀。然后在 Mock 类里实现自己的降级逻辑。 +```java +public class HelloServiceMock implements HelloService { + + public void sayHello() { + // 降级逻辑 + } + +} + +``` + +### 失败重试和超时重试 +所谓失败重试,就是 consumer 调用 provider 要是失败了,比如抛异常了,此时应该是可以重试的,或者调用超时了也可以重试。配置如下: + +```xml + +``` + +举个栗子。 + +某个服务的接口,要耗费 5s,你这边不能干等着,你这边配置了 timeout之后,我等待2s,还没返回,我直接就撤了,不能干等你。 + +可以结合你们公司具体的场景来说说你是怎么设置这些参数的: + +- `timeout`:一般设置为 `200ms`,我们认为不能超过 `200ms`还没返回。 +- `retries`:设置 retries,一般是在读请求的时候,比如你要查询个数据,你可以设置个 retries,如果第一次没读到,报错,重试指定的次数,尝试再次读取。 \ No newline at end of file diff --git a/img/dubbo-service-invoke-road.png b/img/dubbo-service-invoke-road.png new file mode 100644 index 0000000000000000000000000000000000000000..99060ae99ba8268561904cfde9e39258a872f590 GIT binary patch literal 14658 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