架构师 0 期 | 一致性 Hash 算法
架构师训练营第五周作业
用你熟悉的编程语言实现一致性 hash 算法。
编写测试用例测试这个算法,测试 100 万 KV 数据,10 个服务器节点的情况下,计算这些 KV 数据在服务器上分布数量的标准差,以评估算法的存储负载不均衡性。
为啥会有一致性Hash算法?
在分布式系统中,为了平均分配服务器资源,最简单的思路就是随机分配。
对服务器总数进行取模运算,得到的余数就是目标服务器编号。
但是这个算法有个致命的问题,当业务高速发展时,增加服务器时,服务器总数增加,导致取模得到的值全都发生了变化,之前的数据就都错了。对分布式缓存来说,同一时刻,大量缓存失效,会出现缓存雪崩。后果都是灾难性的。
要解决这个问题就需要一个方案,当服务器数据有变化时,尽可能的小的影响现有的这种映射关系。
所以就诞生了一致性Hash算法。
一致性Hash算法原理
一致性哈希算法通过一个叫作一致性哈希环的数据结构实现。
这个环的起点是 0,终点是 2^32 - 1,并且起点与终点连接,故这个环的整数分布范围是 [0, 2^32-1]
这次不再对服务器总数进行取模运算,而是对 2^32进行取模运算,这样得到的值就在这个哈希环上。
将服务器节点放在这个环上。
同样的道理,对缓存的对象进行同样的取模运算。得到的值也在此环上。顺时针寻找下去,将它放在离它最近的服务器里。
即对象k3、k1放在服务器t1上、 k4放在t3上、k2放在t2上。
这样当服务器数据有变化时,受影响的节点就只有离它最近的服务器。当服务器越多时,受到的影响越小。
虚拟节点
以上方案还有个问题是,虽然增减服务器不会影响到太多已有服务。但是提升性能不太明显,只会分担节点顺时针后面的那台服务器,其他的没起到分担负载的作用。
解决方案是,增加虚拟节点。每台服务器虚拟成200个节点,平均散落在哈希环上。
判断Hash算法的好坏
平衡性
哈希的结果能够尽可能分布到所有的集群机器上。
单调性
已经有一部分数据通过哈希算法分配到了相应机器上,又有新的机器加入到集群系统中。哈希的结果应该能够保证原有已分配的数据可以被映射到原有的或者新的机器上,而不是被映射到旧的集群中的其他机器。
分散性
在分布式环境中,终端看不到集群中所有的机器,而是只能看到其中的一部分。当终端希望通过哈希算法将数据映射到机器上时,由于不同终端所见的机器范围有可能不同,从而导致哈希的结果不一致,最终的结果是相同的数据被不同的终端映射到不同的机器上。这种情况显然是应该避免的,这极大地降低了系统存储的效率。分散性的定义就是上述情况发生的严重程度。好的哈希算法应能够尽量避免不一致的情况发生,也就是尽量降低分散性。
负载
既然不同的终端可能将相同的数据映射到不同的机器上,那么对于一个特定的机器而言,也可能被不同的用户映射为不同的数据。与分散性一样,这种情况也是应当避免的,因此好的哈希算法应能够尽量降低机器的负荷。
代码实现
代码目录结构
测试方法,模拟10台服务器,100万个KV数据,分别计算虚拟节点在1个、10个、100个、200个、500个、1000个的时候,标准差是多少。
定义缓存接口类Cache,方便更换实现类。面向接口编程。
接口类中只暴露2个方法,一个get,一个set
实现缓存接口类CacheImplement
重新接口定义方法get、set、toString
构造方法,接收服务器列表和每台服务器虚拟节点数。
将虚拟节点遍历加到hash环上。
具体缓存实现类CacheServer
一致性Hash类
提供向Hash环添加服务器方法
提供通过key,查找对应服务器方法
提供计算HashCode方法
提供打印结果及计算标准差
计算测试结果如下:
不使用虚拟节点的话,偏差很大,最少的是6千多个,最多的是35万多个,很不均衡。
当虚拟节点达到200个时,最少的是9万4千多个,最多的是11万多,差距已经不是很多。
当虚拟节点是1000个时,最小是9万5,最大是10万4,增加300个虚拟节点,收益并不大了。
以下为详细数据
版权声明: 本文为 InfoQ 作者【刁架构】的原创文章。
原文链接:【http://xie.infoq.cn/article/30addf3f4bef660a5b82c2c19】。文章转载请联系作者。
评论 (2 条评论)