深入学习一致性 Hash
什么是一致性Hash算法
一致性哈希算法在1997年由麻省理工学院的Karger等人在解决分布式Cache中提出的,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似。一致性哈希修正了CARP使用的简单哈希算法带来的问题,使得DHT可以在P2P环境中真正得到应用
优点
一致性Hash算法有着更好的容错性和扩展性,无论添加还是删除节点,都只会对一小部分数据有影响。
优秀的一致性Hash算法的特点
平衡性(Balance)
平衡性是指哈希的结果能够尽可能分布到所有的缓冲中去,这样可以使得所有的缓冲空间都得到利用。
单调性(Monotonicity)
单调性是指如果已经有一些内容通过哈希分派到了相应的缓冲中,又有新的缓冲区加入到系统中,那么哈希的结果应能够保证原有已分配的内容可以被映射到新的缓冲区中去,而不会被映射到旧的缓冲集合中的其他缓冲区。
分散性(Spread)
分散性就是在分布式环境中尽量避免因终端无法看所所有缓存节点而导致的相同内容经过哈希只会被映射到不用缓存的情况,因为这样降低了系统存储的效率。
负载(Load)
负载就是只特定的一段缓存被映射为不同的内容的情况,好的哈希算法应能够尽量降低缓冲的负荷。
平滑性(Smoothness)
平滑性是指缓存服务器的数目平滑改变和缓存对象的平滑改变是一致的。
原理
核心概念-Hash环
哈希函数H的值空间定义为0-2^32-1,然后将整个哈希值空间组织成一个虚拟的圆环,整个空间按顺时针方向组织,圆环的正上方的点代表0,0点右侧的第一个点代表1,以此类推,2、3、4、5、6……直到2^32-1,也就是说0点左侧的第一个点代表2^32-1, 0和2^32-1在零点中方向重合,我们把这个由2^32个点组成的圆环称为Hash环
原理详解
具体使用的时候我们是将各个服务进行Hash的,可以选择服务IP或者服务器主机名作为关键字,通过关键字Hash来计算服务器在Hash环上的位置。如下图
四台服务器通过Hash函数计算之后分别映射到了4个节点上,将数据key使用相同的函数Hash计算出哈希值,并确定此数据在环上的位置,从此位置沿环顺时针“行走”,第一台遇到的服务器就是其应该定位到的服务器。
当我们新增一台服务的时候,只有新增服务器所在的Hash环节点和它上一个节点之间的key收到的了影响,如下图:
当新增服务器X时候,原来映射到Node c的的Object 2映射到了Node x上了,Hash环上Node B 到Node X之间的key映射结果对应的服务器改变了,其它key未收到的影响。
当有一台服务宕机了的时候,情况如下图
当服务器B宕机之后,原本映射到服务Node B的Object 1变为映射到Node C了,整个Hash环上,只有Node A到Node B之间的key映射结果受到了影响。
综上所述,一致性哈希算法对于节点的增减都只需重定位环空间中的一小部分数据,具有较好的容错性和可扩展性
虚拟节点
一致性哈希算法在服务节点太少时,容易因为节点分部不均匀而造成数据倾斜问题。为了解决这种数据倾斜问题,一致性哈希算法引入了虚拟节点机制,即对每一个服务节点计算多个哈希,每个计算结果位置都放置一个此服务节点,称为虚拟节点。具体做法可以在服务器ip或主机名的后面增加编号来实现。
实现
ConsistentHash.java的具体实现如下
通过标准差反应一致性Hash的均衡性
采用MD5 hash算法,10台服务器,100个虚拟节点,100w的key来验证一致性Hash算法的均衡性
输出结果如下:
调整虚拟节点的结果影响如下:
从结果来看增加虚拟节点可以有效的提高均衡性
不同Hash算法的均衡性验证
采用10台服务器,100个虚拟节点,100w的key来分别验证DubboHash、Fnv132Hash、Fnv1A32Hash、JDK默认Hash、MurMurHash、OneAtATimeHash的均衡性
从结果上看Dubbo采用的hash函数均衡性较好,DubboHash 其实就是MD5方式的Hash 函数,具体实现如下:
guava中提供的一致性hash
Guava中有一个Hashing类简单实现了一个一致性哈希的算法
源码
均衡性效果
采用Md5Hash算法,10台服务器,100个虚拟节点,100w的key来分别验证guava一致性hash算法的均衡性效果如下
标准差:287.63483794561466
从结果上来看guava的一致性hash算法均衡性非常好,而且使用简单,我们可以在均衡性要求较高的场景使用
版权声明: 本文为 InfoQ 作者【拈香(曾德政)】的原创文章。
原文链接:【http://xie.infoq.cn/article/62570be37e06cec263882343e】。文章转载请联系作者。
评论