架构师训练营第五周作业——一致性哈希算法
设计
本文将描述基于虚拟节点的一致性哈希算法的实现,实现语言为 Java。
一致性 hash 环需要一个以 hash 值为 Key 的容器,且该容器能方便地实现插入、删除、查找最近节点等操作,Java 中 SortedMap 接口满足该条件,实现类可以使用 TreeMap
各节点命中次数的标准差,可以用来作为衡量节点负载均衡程度,假设节点 i 的命中次数为 Hi,平均命中次数为 Havg,标准差的计算公式为:
实现
节点
一致性哈希算法
测试类
结论
运行以上测试类 5 次,每次生成 100 万 hash 测试,统计结果如下,表格中为不同虚拟节点数对应的标准差:
由以上图标基本可以看出,150 虚拟节点之内,标准差随虚拟节点数增加显著下降,而 150 至 250 之间有波动。当然测试次数比较少,不能因此说多少虚拟节点数是最好的,但大致趋势还是能看出来的。
思考
以上算法中,虚拟节点位置随机,因此不可能完全均匀分布,要想使环上虚拟节点均匀分布,那么有可能还是需要干预。
假设我们希望每台缓存服务器的负载完全均衡,也就是说只有一台服务器的时候,其负载是总负载的 100%,两台的时候每台负载是总负载的 50%,三台的时候每台是 33.33%,以此类推,N 台服务器,每台的负载时总负载的 1/N,这时候如果再增加一台服务器,每台负载由 1/N 降至 1/(N+1)
可能的算法,增加第 N 台服务器节点时,假设此时环上已经有 V 个虚拟节点,那么,这 V 个虚拟节点将环切割成 V 段,如果想要第 N 台服务器加入以后,每台服务器的负载为 1/N,我们可以再环上每一段的前 1/N 增加一个对应服务器 N 的虚拟节点,这个虚拟节点分担所在段的 1/N 压力,V 段新增的虚拟节点分担的压力之和也就是整个环的 1/N。以下是这个过程的模拟:
最初只有一台服务器(标记为 1),整个环只有 1 段;
加入第二台服务器时,在环的 1/2 处新增节点(标记为 2),将环分成两段;
增加第三台服务器时,在原来的两段的前 1/3 各增加一个节点(标记为 3),将环分为四段,增加第四台机器时,又在原来的四段的前 1/4 增加一个虚拟节点,以此类推
实现
继承 ConsistentHash,覆盖 addNode 方法
验证
测试 10-40 台服务器节点时的标准差,从下图可以看到,标准差基本在 300 以下,这相对于 1000000 的基数来说还是挺小的。
这个算法也存在很明显的问题,那就是节点数量指数增长,放置第 N 台服务器节点时,需要增加 2^(N-2)个虚拟节点,当然随着虚拟节点数增多,部分虚拟节点会重合,但虚拟节点的总数也非常大,因此新增节点的效率会比较低
版权声明: 本文为 InfoQ 作者【文智】的原创文章。
原文链接:【http://xie.infoq.cn/article/2a76cf0630f00171d027a83b1】。未经作者许可,禁止转载。
评论