Dubbo cluster fault tolerance and load balancing strategy

Dubbo cluster fault tolerance strategy
Normally, when we design the system, not only to consider the normal logic of the code under Gairuhezou, should also be considered in exceptional circumstances should be how to get the code logic. When the service consumer calls the service provider when the service error occurs, Dubbo offers a variety of fault-tolerant programs, the default mode for the failover, which is the failure to try again.
Fault-tolerant cluster model provided Dubbo
The following look at the fault-tolerant cluster mode Dubbo provided:
Failover Cluster: failure retry
When the service consumer calls the service provider fails to automatically switch to another service provider server to try again. This is typically used to write or read operation has such power, it should be noted that the retry will bring a longer delay. Through retries = "2" to set the number of retries (excluding the first).
Interface Level Configuration retries method <dubbo: reference retries = "2" />, as configured when the service consumer invokes the service fails, try again twice, which means that most will do three calls, here's configuration all methods of the interface takes effect. Of course, you can also configure the number of retries for a method as follows:
[XML]  plain text view  Copy the code
?
1
2
< dubbo:reference >[/size][/font][/color][/align]    < dubbo:method name = "sayHello" retries = "2" />
</ dubbo:reference >

Failfast Cluster: Quick fail
When the service consumer calls the service provider fails, the error immediately, which is called only once. This mode is typically used for non-idempotent write operation.
Failsafe Cluster: Fail Safe
When an exception occurs service consumer invokes the service directly ignore the exception. This mode is often used for operations such as writing the audit log.
Failback Cluster: automatic failure recovery
When an exception occurs with the service consumer side service, in the background of the recording request fails, and then retry according to certain post-strategy. This mode is often used for message notification operation.
Forking Cluster: Parallel call
When a consumer calls the interface method, Dubbo Client will call multiple concurrent service providers, as long as a success that is returned. This mode is often used for higher real-time requirements of a read operation, but more services need to waste resources. May = "2" to set the maximum number of parallel through the forks.
Broadcast Cluster: Broadcast call
When a consumer calls the interface method, Dubbo Client will call one by one all the service providers, call Renyiyitai exception is the call sign on failure. This mode is often used to inform all providers such as cache or log updates the local resource information.
Above, Dubbo itself provides a rich cluster fault-tolerant mode, but if you have customization requirements, can be customized according to the expansion interface Cluster Dubbo provided. In the back of the consumer section will explain the process boot cluster fault tolerance when / how to use it.
Failure retry policy implementation analysis
Dubbo in the concrete realization of the failure of retries is FailoverClusterInvoker class, where we look at the specific implementation, mainly look doInvoke Code:
[Java]  plain text view  Copy the code
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers,LoadBalance loadbalance) throws RpcException{
     // (1) 所有服务提供者
     List<Invoker<T>> copyinvokers = invokers;
     checkInvokers(copyinvokers,invocation);
 
     // (2)获取重试次数
     int len  = getUrl().getMethodParameter(invocation.getMethodName(),Constants.RETRIES_KEY,Constants.DEFAULT_RETRIES) + 1 ;
     if (len <= 0 ){
         len = 1 ;
     }
     
     // (3)使用循环,失败重试
     RpcException le = null ;    // last exception
     List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(copyinvokers.size());
     Set<String> providers = new HashSet<String>();
     for ( int i= 0 ;i<len;i++){
         // 重试时,进行重新选择,避免重试时invoker列表已发生变化
         // 注意:如果列表发生了变化,那么invoked判断会失效,因为invoker示例已经改变
         if (i > 0 ){
             // (3.1)
             checkWhetherDestroyed();    // 如果当前实例已经被销毁,则抛出异常
             // (3.2) 重新获取所有服务提供者
             copyinvokers = list(invocation);
             // (3.3) 重新检查一下
             checkInvokers(copyinvokers,invocation);
         }
         // (3.4) 选择负载均衡策略
         Invoker<T> invoker = select(loadbalance,invocation,copyinvokers,invoked);
         invoked.add(invoker);
         RpcContext.getContext().setInvokers((List)invoked);
         // (3.5) 具体发起远程调用
         try {
             Result result = invoker.invoke(invocation);
             if (le != null && logger.isWarnEnabled()){
                 ...
             }
             return result;
         } catch (RpcException e){
             if (e.isBiz()){    // biz exception
                 throw e;
             }
             le = e;
         } catch (Throwable e){
             le = new RpcException(e.getMessage(),e);
         } finally {
             providers.add(invoker.getUrl().getAddress());
         }
     }
     throw new RpcException( "抛出异常..." );
}
  • As the code (2) the number of retries acquired from url parameter set which, if the user does not set the default value taken, default retry 2 to note here is that the code (2) is to obtain the number of retries to +1 and a. This shows that the total number of calls = number of retries + 1 (1 is the normal call).
  • Code (3) cycle is repeated trial, if the first call is successful direct return out of the loop, otherwise the loop and try again. Code will not go (3.1) (3.2) (3.3) during the first call. If an exception occurs first call, it will cycle, this time i = 1, it will execute the code (3.1) Check for a thread calls the current ReferenceConfig destroy () method, the destruction of the current consumer. If the current instance has been consumer spending, then retry does not make sense, so RpcException will throw an exception.
  • If the current instance of the consumer has not been destroyed, then execute the code (3.2) retrieve the current list of service providers, this is the first time since the transfer began to thread may have changed the provider list, after obtaining the list, and then execute (3.2 ) were once again check. Verification is performed by (3.4), according to the load balancing policy to select a service provider, try calling again. Under section select load balancing strategy will explain.
Dubbo load balancing strategy
当服务提供方是集群的时候,为了避免大量请求一直落到一个或几个服务提供方机器上,从而使这些机器负载很高,甚至打死,需要做一定的负载均衡策略。Dubbo提供了多种均衡策略,缺省为random,也就是每次随机调用一台服务提供者的机器。
Dubbo提供的负载均衡策略
  • Random LoadBalance:随机策略。按照概率设置权重,比较均匀,并且可以动态调节提供者的权重。
  • RoundRobin LoadBalance:轮询策略。轮询,按公约后的权重设置轮询比率。会存在执行比较慢的服务提供者堆积请求的情况,比如一个机器执行的非常慢,但是机器没有挂调用(如果挂了,那么当前机器会从Zookeeper的服务列表删除),当很多新的请求到达该机器后,由于之前的请求还没有处理完毕,会导致新的请求被堆积,久而久之,所有消费者调用这台机器上的请求都被阻塞。
  • LeastActive LoadBalance:最少活跃调用数。如果每个提供者的活跃数相同,则随机选择一个。在每个服务提供者里面维护者一个活跃数计数器,用来记录当前同时处理请求的个数,也就是并发处理任务的个数。所以如果这个值越小说明当前服务提供者处理的速度很快或者当前机器的负载比较低,所以路由选择时候就选择该活跃度最小的机器。如果一个服务提供者处理速度很慢,由于堆积,那么同时处理的请求就比较多,也就是活跃调用数目越大,这也使得慢的提供者收到更少请求,因为越慢的提供者的活跃度越来越大。
  • ConsistentHash LoadBalance:一致性Hash策略。一致性Hash,可以保证相同参数的请求总是发到同一提供者,当某一台提供者挂了时,原本发往该提供者的请求,基于虚拟节点,平摊到其他提供者,不会引起剧烈变动。
一致性Hash负载均衡策略原理
在解决分布式系统中,负载均衡的问题可以使用Hash算法让固定的一部分请求落到同一台服务器上,这样每台服务器固定处理一部分请求(并维护这些请求的信息),起到负载均衡的作用。
但是普通的余数Hash(Hash(比如用户id)%服务器机器数)算法伸缩性很差,当新增或者下线服务器机器时候,用户id与服务器的映射关系会大量失效。一致性Hash则利用Hash环对其进行了改进。
一致性Hash概述
为了能直观的理解一致性Hash的原理,这里结合一个简单的例子来讲解,假设有4台服务器,地址为ip1/ip2/ip3/ip4 。
  • 一致性Hash,首先计算四个ip地址对应的Hash值:hash(ip1) / hash(ip2) / hash(ip3) / hash(ip4) ,计算出来的Hash值是0~最大正整数之间的一个值,这四个值在一致性Hash环上呈现如下图:

  • Hash环上顺时针从整数0开始,一直到最大正整数,我们根据四个ip计算的Hash值肯定会落到这个Hash环上的某一个点,至此我们把服务器的四个ip映射到了一致性Hash环。
  • 当用户在客户端进行请求时候,首先根据Hash(用户id)计算路由规则(Hash值),然后看Hash值落到了Hash环的哪个地方,根据Hash值在Hash环上的位置顺时针找距离最近的ip作为路由ip。

如上图可知user1 / user2的请求会落到服务器 ip2 进行处理,user3的请求会落到服务器ip3进行处理,user4的请求会落到服务器ip4进行处理,user5 / user6 的请求会落到服务器ip1进行处理。
下面考虑当ip2的服务器挂了的时候会出现什么情况?
当ip2的服务器挂了的时候,一致性Hash环大致如下图:
<ignore_js_op>
根据顺时针规则可知user1 / user2的请求会被服务器ip3进行处理,而其他用户的请求对应的处理服务器不变,也就是只有之前被ip2处理的一部分用户的映射关系被破坏了,并且其负责处理的请求被顺时针下一个节点委托处理。
下面考虑当有新增机器加入时会出现什么情况?
当新增一个ip5的服务器后,一致性Hash环大致如下图:
<ignore_js_op>
根据顺时针规则可知之前user1的请求应该被ip1服务器处理,现在被新增的ip5服务器处理,其他用户的请求处理服务器不变,也就是新增的服务器顺时针最近的服务器的一部分请求会被新增的服务器所替代。
一致性Hash的特性
一致性Hash有要有以下特性:
  • 单调性(Monotonicity),单调性是指如果已经有一些请求通过哈希分派到了相应的服务器进行处理,又有新的服务器加入到系统中时,应保证原有的请求可以被映射到原有的或者新的服务器中去,而不会被映射到原来的其他服务器上去。这一点通过上面新增服务器ip5可以证明,新增ip5后,原来被ip1处理的user6现在还是被ip1处理的user5现在被新增的ip5处理。
  • 分散性(Spread):分布式环境中,客户端请求时候可能不知道所有服务器的存在,可能只知道其中一部分服务器,在客户端看来它看到的部分服务器会形成一个完整的Hash环,那么可能会导致,同一个用户的请求被路由到不同的服务器进行处理。这种情况显然是应该避免的,因为它不能保证同一个用户的请求落到同一个服务器。所谓分散性是指上述情况发生的严重程度。
  • 平衡性(Balance),平衡性也就是说负载均衡,是指客户端Hash后的请求应该能够分散到不同的服务器上去。一致性Hash可以做到每个服务器都进行处理请求,但是不能保证每个服务器处理的请求的数量大致相同,如下图:
<ignore_js_op> 
服务器ip1 / ip2 / ip3经过Hash后落到了一致性Hash环上,从图中Hash值分布可知ip1会负责处理大概80%的请求,而ip2和ip3则只会负责处理大概20%的请求,虽然三个机器都在处理请求,但是明显每个机器的负载不均衡,这样称为一致性Hash的倾斜,虚拟节点的出现就是为了解决这个问题。
虚拟节点
当服务器节点比较少的时候会出现上节所说的一致性Hash倾斜的问题,一个解决方法是多加机器,但是加机器是有成本的,那么就加虚拟节点,比如上面三个机器,每个机器引入1个虚拟节点后的一致性Hash环如下图所示:
<ignore_js_op>
其中ip1-1是ip1的虚拟节点,ip2-1是ip2的虚拟节点,ip3-1是ip3的虚拟节点。
可知当物理机器数目为M,虚拟节点为N的时候,实际hash环上节点个数为 M*(N+1) 。比如当客户端计算的Hash值处于ip2和ip3或者处于ip2-1和ip3-1之间时候使用ip3服务器进行处理。
均匀一致性Hash
上节我们使用虚拟节点后的图看起来比较均衡,但是如果生成虚拟节点的算法不够好很可能会得到下面的环:
<ignore_js_op>
可知每个服务节点引入1个虚拟节点后,情况相比没有引入前均衡性有所改善,但是并不均衡。
均衡的一致性Hash应该如下图所示:
<ignore_js_op>
均匀一致性Hash的目标是如果服务器有N台,客户端的Hash值有M个,那么每个服务器应该处理大概 M/N 个用户的请求。也就是每台服务器均衡尽量均衡。Dubbo提供的一致性Hash就是不均匀的,这个大家可以去研究下ConsistentHashLoadBalance类。
转载https://www.cnblogs.com/xhj123/p/9087532.html
更多技术资讯可关注:itheimaGZ获取

Guess you like

Origin www.cnblogs.com/zhuxiaopijingjing/p/12298104.html