前言
前面一篇文章提到了服务的消费,到最后还有一段关于集群的代码,在实际的生产环境中,zookeeper会有集群来提高服务的容错能力,所以dubbo编写了集群的代码去解决这个问题,集群一定会涉及到负载均衡,负载均衡的耦合性比较低适合单独拿出来分析,所以这一期介绍一下dubbo几种负载均衡策略以及实现
正文
dubbo负载均衡的接口是LoadBalance,使用了SPI注解
接口只有一个select方法,传入一个可供选择的invokers,返回选择的invoker
AbstractLoadBalance继承了LoadBalance接口,并且定义了一个抽象方法doSelect,用于子类实现的模板方法。
只有一个invoker直接返回
AbstractLoadBalance提供了一个计算服务提供者权重的方法,注释都写在内部了
继承了AbstractLoadBalance一共有四个类,分别代表了不同的负载均衡策略:
- ConsistentHashLoadBalance:一致性hash
- RoundRobinLoadBalance:轮询
- RandomLoadBalance:随机
- LeastActiveLoadBalance:最少活跃数
下面分别介绍每种策略的实现细节
RandomLoadBalance 随机负载均衡
随机选择是最简单的,直接看代码,注释写得很明白 标题
RoundRobinLoadBalance 轮询负载均衡
轮询负载均衡的难点是带权重的轮询
比如一个有三个服务:[A,B,C],权重:[3,2,1],当进行6次负载均衡以后,A、B、C三台服务器选择的次数分别为3,2,1
dubbo采用的方法是:
- 初始化服务,维护一个current参数,初始化为0
- 遍历每个服务,各自加上自己的权重,权重最大的被选中。
- 被选中的服务减去总权重
- 重复上面的步骤
轮询过程,6次轮询,A服务3次,B服务2次,C服务1次
代码
用WeightedRoundRobin类来维护服务信息,用methodWeightMap来保存方法->多个服务map
前面部分是创建map和获取key的操作,红框圈起来是核心业务代码,自增、计算weight的total和找到最大权重的服务。
这一段代码是新加入了服务,或者是太长没有被选择服务,调整methodWeightMap
最后就是选中的服务减去总权重,然后返回服务
LeastActiveLoadBalance 最小活跃负载均衡
首先初始化信息
然后遍历每个服务,遇到了最小的活跃数就重新计算,如果有相同的活跃度,则同样加入数组中。
经过上面的操作后,会选出几个具有相同活跃度的服务,如果只有一个就直接返回,有多个的话根据权重按照之前介绍的随机方法进行选择。
ConsistentHashLoadBalance 一致性hash负载均衡
一致性Hash的原理是将服务化成一个环
将数据Key使用相同的函数Hash计算出哈希值,并确定此数据在环上的位置,从此位置沿环顺时针查找,遇到的服务器就是其应该定位到的服务器
由于
对服务Ip加上编号,形成更多的虚拟IP,让一致性Hash的负载更加均衡
代码
使用一个Map,Value为ConsistentHashSelector来保存不同方法对应的集群,注意identityHashCode这个方法,它的返回值是原始的hashCode方法返回值一致,修改了hashCode也不会改变,这里有个Bug就是,如果传入invokers的时候对这个List做了stream操作,会导致list的地址改变,使这个map缓存无效。
进入ConsistentHashSelector类
使用了TreeMap来作为节点hash的映射,因为TreeMap是树结构,能够更快的求出大于\小于的所有节点。
有关于一致性Hash的配置如下:
//需要哪些参数来生成hashCode,如果invoker(Obecjt var1,Object var2) 默认值为0,代表只使用var1来生成hashCode<dubbo:parameter key="hash.arguments" value="0,1" />//虚拟节点的数量,默认为160<dubbo:parameter key="hash.nodes" value="320" />复制代码
根据Invoker和方法名称来初始化ConsistentHashSelector
红框部分:将所有的虚拟机节点4个分为一组,根据md5算法为每4个结点生成一个消息摘要,摘要长为16字节128位。然后通过hash算法计算出md5的hash值,放入TreeMap
主要方法是selectForKey,使用TreeMap的tailMap方法,能够获取大于该hash值的所有服务,通过firstEntry获取大于的第一个服务,由于是一个环状结构,entry为空的话就获取TreeMap的第一个服务节点。
结尾
介绍了dubbo四种负载均衡策略,这四种也是比较常见的负载均衡算法,在Spring Cloud中也有体现,这里可以看出来实现还是比较容易。