dubbo的负载均衡可以分为两个方面,一个是对多注册中心的负载均衡,一个是对多服务的负责均衡。dubbo的负载均衡类继承关系图如下:
这篇文章对代码进行了解析:https://www.cnblogs.com/wyq178/p/9822731.html
在org.apache.dubbo.rpc.cluster.loadbalance.AbstractLoadBalance#getWeight方法里面,对权重进行了计算,计算过程涉及到两个参数:uptime和warmup。
uptime=当前系统时间-服务端服务发布时间,该字段表示截止到现在服务运行了多久;
warmup是服务端配置的,表示服务需要的预热时间,该参数需要配置到spring配置文件中,如下:dubbo.provider.warmup=10000,服务端所有的服务预热时间都是这个值,单位是毫秒。
从上图可以看出,权重默认是100,权重最小是0,。如果服务端配置了预热时间warmup,且当前服务端还在预热期内,那么权重需要等比例的调低,权重=(已启动时间/预热时间)*权重。
上面介绍完了权重计算规则。下面介绍一下负载均衡各个实现类的功能。每个负载均衡实现类都需要实现doSelect方法。其中doSelect方法的invoks入参表示所有可用服务的List集合。
RandomLoadBalance
这是使用随机算法的负载均衡,如果每个服务的权重相同,使用代码返回对应服务下标,也就是入参invoks的下标:
ThreadLocalRandom.current().nextInt(length)
length表示服务总个数。
如果权重不同,选择服务的方式如下:
假如有五个服务,每个服务的权重为:服务S1权重100,服务S2权重200,服务S3权重140,服务S4权重230,服务S5权重300,计算出的offset=364。那么选中的服务是364-S1-S2-S3<0,所以选择服务S3。
RoundRobinLoadBalance
该类相当于轮询算法。当所有的服务权重相同时,会按照入参invoks集合从下标0开始顺次遍历使用每个服务。但是当权重不同时,遍历的顺序会有所不同。
在该类中使用了类WeightedRoundRobin,该类会记录每个服务的当前权重weight、历史权重current和最后一次遍历时间lastUpdate。其中历史权重初始化为0。
WeightedRoundRobin对象记录了服务最后一次遍历时间lastUpdate,如果发现一个服务的最后一次遍历时间与现在间隔了超过了60000毫秒,那么该服务对应的WeightedRoundRobin对象会被销毁。
该算法经历了多次修改,最新版本是2.7.5,该版本的算法是参考了Nginx。具体内容参见官网:
http://dubbo.apache.org/zh-cn/docs/source_code_guide/loadbalance.html
LeastActiveLoadBalance
该类是最小活跃数负载均衡,该算法认为活跃数越小,说明服务响应越快,自然被调用的概率越大。使用该负载均衡算法需要启用过滤器ActiveLimitFilter,在ActiveLimitFilter过滤器中对活跃数增减。
最小活跃数使用类RpcStatus记录,该类中有个常量METHOD_STATISTICS,记录每个服务对应的RpcStatus对象,RpcStatus对象的active属性即是服务活跃数。
当选出了所有的活跃数最小的服务后,然后使用RandomLoadBalance的算法,从这些服务中选出一个服务返回。
ActiveLimitFilter过滤器用于修改活跃数,当时客户端发起一次调用时,会增加1,服务端调用返回后,活跃数再减1。所以在多线程环境下,服务被多次同时调用,在服务端返回前,这些服务的活跃数都不为1,如果某个服务的响应速度非常快,那么其活跃数也会比较小。默认ActiveLimitFilter过滤器不会被启用,我们需要配置actives属性,比如:使用注解@Reference(actives=10)
ConsistentHashLoadBalance
该类使用一致性哈希算法,该类也是唯一一个忽略了权重和预热时间的算法。大家可以先在网上看一下一致性哈希算法的原理。
该类的流程是:
上述流程图中涉及到两个参数hash.nodes和hash.arguments。这两个参数的注解配置方式是:@Reference(parameters={"hash.nodes","320","hash.arguments","1,2"}),该注解的含义是hash.nodes=320,hash.arguments=1,2。
hash.arguments:当调用远程服务的时候根据服务的哪几个参数生成key,并根据key来通过一致性hash算法来选择调用节点。默认是0,如果要选取多个参数,中间用逗号分隔,比如:“1,2,3”。假如入参为args[],hash.arguments=1,2,那么上图中计算请求值的md5=md5(args[1].toString()+args[2].toString())
hash.nodes:为虚拟节点的副本数。默认是160,也就是说每个服务在圆环上存在160个虚拟节点。
一致性哈希算法中的圆环使用TreeMap表示。
如果远程服务没有请求参数,例如calAccount(),那么在入参Invokers集合不变的前提下,任何对远程服务的调用都一直返回相同的Invoker。
源代码解析可以参考官网:
http://dubbo.apache.org/zh-cn/docs/source_code_guide/loadbalance.html