作者:FserSuN
来源:https://blog.csdn.net/Revivedsun/article/details/71022871
LoadBalance负责从多个Invoker中选出具体的一个用于本次调用,以分摊压力。Dubbo中LoadBalance结构如下图。
1 | com.alibaba.dubbo.rpc.cluster.LoadBalance |
1 | com.alibaba.dubbo.rpc.cluster.loadbalance.AbstractLoadBalance |
一致性哈希负载均衡配置
具体的负载均衡实现类包括4种。分别是随机、轮训、最少活跃、一致性Hash
一致性哈希负载均衡配置
配置如:
1 | <dubbo:service interface="..." loadbalance="consistenthash" /> |
一致性Hash负载均衡涉及到两个主要的配置参数为hash.arguments 与hash.nodes。
hash.arguments : 当进行调用时候根据调用方法的哪几个参数生成key,并根据key来通过一致性hash算法来选择调用结点。例如调用方法invoke(String s1,String s2); 若hash.arguments为1(默认值),则仅取invoke的参数1(s1)来生成hashCode。
hash.nodes: 为结点的副本数。
1 | 缺省只对第一个参数Hash,如果要修改,请配置 |
Dubbo中一致性Hash的实现分析
dubbo的一致性哈希通过ConsistentHashLoadBalance类来实现。
ConsistentHashLoadBalance内部定义ConsistentHashSelector类,最终通过该类进行结点选择。ConsistentHashLoadBalance实现的doSelect方法来利用所创建的ConsistentHashSelector对象选择结点。
doSelect的实现如下。当调用该方法时,如果选择器不存在则去创建。随后通过ConsistentHashSelector的select方法选择结点。
1 | "unchecked") ( |
ConsistentHashSelector在构造函数内部会创建replicaNumber个虚拟结点,并将这些虚拟结点存储于TreeMap。随后根据调用方法的参数来生成key,并在TreeMap中选择一个结点进行调用。
1 | private static final class ConsistentHashSelector<T> { |
上述代码中 hash(byte[] digest, int number)方法用来生成hashCode。该函数将生成的结果转换为long类,这是因为生成的结果是一个32位数,若用int保存可能会产生负数。而一致性hash生成的逻辑环其hashCode的范围是在 0 - MAX_VALUE之间。因此为正整数,所以这里要强制转换为long类型,避免出现负数。
进行结点选择的方法为select,最后通过sekectForKey方法来选择结点。
1 | // 选择结点 |
sekectForKey方法的实现如下。
1 | private Invoker<T> sekectForKey(long hash) { |
在进行选择时候若HashCode直接与某个虚拟结点的key一样,则直接返回该结点,例如hashCode落在某个结点上(圆圈所表示)。若不在,找到一个最小上届的key所对应的结点。例如进行选择时的key落在图中1所标注的位置。由于利用TreeMap存储,key所落在的位置可能无法找到最小上界,例如图中2所标注的位置。那么需要返回TreeMap中的最小值(构成逻辑环状结构,找不到,则返回最开头的结点)。
如果大家喜欢我的文章,可以关注个人订阅号。欢迎随时留言、交流。