Dubbo集群容错与负载均衡策略
- 2019 年 12 月 20 日
- 筆記
一、 Dubbo集群容错策略概述
当我们进行系统设计时候,不仅要考虑正常逻辑下代码该如何走,还要考虑异常情况下代码逻辑应该怎么走。当服务消费方调用服务提供方的服务出现错误时候,Dubbo 提供了多种容错方案,缺省模式为 failover,也就是失败重试。
下面看下 Dubbo 提供的集群容错模式:
- Failover Cluster:失败重试
当服务消费方调用服务提供者失败后自动切换到其他服务提供者服务器进行重试。这通常用于读操作或者具有幂等的写操作,需要注意的是重试会带来更长延迟。可通过 retries="2" 来设置重试次数(不含第一次)。
接口级别配置重试次数方法可以使用<dubbo:reference retries="2" />
,如上配置当服务消费方调用服务失败后,会再重试两次,也就是说最多会做三次调用,这里的配置对该接口的所有方法生效。
当然你也可以针对某个方法配置重试次数如下:
<dubbo:reference> <dubbo:method name="sayHello" retries="2" /> </dubbo:reference>
- Failfast Cluster:快速失败
当服务消费方调用服务提供者失败后,立即报错,也就是只调用一次。通常这种模式用于非幂等性的写操作。
- Failsafe Cluster:安全失败
当服务消费者调用服务出现异常时,直接忽略异常。这种模式通常用于写入审计日志等操作。
- Failback Cluster:失败自动恢复
当服务消费端调用服务出现异常后,在后台记录失败的请求,并按照一定的策略后期再进行重试。这种模式通常用于消息通知操作。
- Forking Cluster:并行调用
当消费方调用一个接口方法后,Dubbo Client 会并行调用多个服务提供者的服务,只要一个成功即返回。这种模式通常用于实时性要求较高的读操作,但需要浪费更多服务资源。如下代码可通过 forks="4" 来设置最大并行数:
<dubbo:reference id="userService" interface="com.test.UserServiceBo" group="dubbo" version="1.0.0" cluster="forking"> <dubbo:parameter key="forks" value="4" /> </dubbo:reference>
- Broadcast Cluster:广播调用
当消费者调用一个接口方法后,Dubbo Client 会逐个调用所有服务提供者,任意一台调用异常则这次调用就标志失败。这种模式通常用于通知所有提供者更新缓存或日志等本地资源信息。
如上,Dubbo 本身提供了丰富的集群容错模式,但是如果您有定制化需求,可以根据 Dubbo 提供的扩展接口 Cluster 进行定制。
在《Dubbo服务消费流程剖析》一节中我们知道服务消费端具体是调用了集群容错策略的doInvoke方法,所以下面我们主要剖析几种比较常见的集群容错的doInvoke方法,以及如何自定义集群容错策略,另外所有集群容错策略都是继承自抽象类AbstractClusterInvoker。
首先我们来看下服务消费端发起远程调用的一个简化时序图,如下图6.1.1:
image.png
图6.1.1
如上时序图图6.1.1采用默认的FailOver集群容错方法时候调用时序图,可知调用集群容错是在服务降级策略后面进行的,集群容错FailoverClusterInvoker内部首先会调用父类AbstractClusterInvoker的list方法来获取invoker列表,可知是从RegistryDirectory管理的RouterChain的route方法获取保存的invoker列表(可以翻看《Directory目录与Router路由服务》一节进行回顾)
下面几章我们对各种集群容错策略源码进行分析。
二、 Dubbo负载均衡策略概述
当服务提供方是集群的时候,为了避免大量请求一直落到一个或者几个服务提供方机器上,从而使这些机器负载很高,甚至打死,需要做一定的负载均衡策略。Dubbo 提供了多种均衡策略,缺省为 random ,也就是每次随机调用一台服务提供者的服务。
Dubbo 提供的负载均衡策略有如下几种:
- Random LoadBalance:随机策略。按照概率设置权重,比较均匀,并且可以动态调节提供者的权重。
- RoundRobin LoadBalance:轮循策略。轮循,按公约后的权重设置轮循比率。会存在执行比较慢的服务提供者堆积请求的情况,比如一个机器执行的非常慢,但是机器没有挂(如果挂了,那么当前机器会从 ZooKeeper 的服务列表删除),当很多新的请求到达该机器后,由于之前的请求还没处理完毕,会导致新的请求被堆积,久而久之,所有消费者调用这台机器上的请求都被阻塞。
- LeastActive LoadBalance:最少活跃调用数。如果每个提供者的活跃数相同,则随机选择一个。在每个服务提供者里面维护着一个活跃数计数器,用来记录当前同时处理请求的个数,也就是并发处理任务的个数。所以如果这个值越小说明当前服务提供者处理的速度很快或者当前机器的负载比较低,所以路由选择时候就选择该活跃度最小的机器。如果一个服务提供者处理速度很慢,由于堆积,那么同时处理的请求就比较多,也就是活跃调用数目越大,这使得慢的提供者收到更少请求,因为越慢的提供者的活跃度越来越大。
- ConsistentHash LoadBalance 一致性 Hash 策略。一致性 Hash,可以保证相同参数的请求总是发到同一提供者,当某一台提供者挂了时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。
如上所述Dubbo提供了丰富的负载均衡策略,但是如果您有定制化需求,可以基于 Dubbo 提供的扩展接口 LoadBalance 进行定制。
AbstractLoadBalance实现了LoadBalance接口,上面的各种负载均衡策略是继承了AbstractLoadBalance方法,但是重写了其doSelect方法,所以下面我们重点看每种负载均衡策略的doSelect方法。
这里我们先看下从消费端发起请求到处理负载均衡的时序图,如下图6.9.1:
image.png
图6.9.1
如上时序图6.9.1,消费端发起远程调用后会先经过步骤4进行服务降级检查,发现没有设置降级策略会执行步骤5进入集群容错invoker,其内部会先执行步骤6从RegistryDirectory里面获取经过服务路由规则过滤后的服务提供者的invokers列表,然后执行代码8到11根据具体负载均衡策略从invoker列表选择一个invoker,最后使用选择的invoke执行步骤12发起远程调用。
下面几章我们对各种负载均衡策略源码进行分析。
三、总结
Dubbo框架提供了几种常见的Dubbo集群容错与负载均衡策略,当业务需要定制时,可以基于SPI接口进行定制。本章摘录自《深度剖析Apache Dubbo核心技术内幕》