一致性哈希算法(consistent hashing)

原文转载于: http://www.javaranger.com/archives/1781


在分布式系统中,如果某业务可以由多个相同的节点处理,很容易想到用HASH的方式将业务请求分散到这些节点处理,如果有N个节点,计算方法为:HASH(id)% N。

如果只是简单的计算,不涉及用户状态,这是一个简单有效的方案。如果节点的计算涉及用户状态,比如Memcache缓存服务等,好像也没什么问题,只要用同一个数据做id,上述HASH的结果也保持不变。但如果节点数量发生变化,比如由于业务量的增大而增加节点或由于机器宕机而减少节点,上述HASH的结果就不一样了。若增加2个节点,某id原处理节点为HASH(id)% N,新的处理节点就变成了HASH(id)% (N + 2),可能会将大量id的处理节点打乱重新分配,就会发现之前某节点保存的用户数据用不到了,而新的处理节点根本没有这些数据。在这段时间内,这些用户的状态受到破坏,如果是缓存服务,之前的缓存都消失了,起不到缓存的效果,可能需要从数据库更新缓存,压力瞬间冲向后端。

一致性哈希在一定程度上缓解了这个问题,步骤为:
1.将整个哈希值空间组织成一个虚拟圆环,假设某哈希函数H的值空间为0-(2^32-1),即32位无符号整数
2.将各节点用H函数哈希,可以将服务器的IP或主机名作为关键字哈希,这样每个节点就能确定其在哈希环上的位置
3.将id用H函数映射到哈希空间的一个值,沿该值向后,将遇到的第一个节点做为处理节点
下图中,若某id的HASH值落在node1和node2各自HASH值的中间位置,则此id对应的业务请求由node2处理。

hash1

当增加服务节点时,只会影响与之相邻的某一节点,其他节点不受影响。如果在node2和node4之间增加一个node5,则只有node4处理的部分id(HASH值落在node2之后、node5之前的那部分id)变为由node5来处理,其他节点处理的id不变。比开头所述的简单HASH方式有了很大的改善。

hash2

如果节点数不多,将这些节点映射到值空间之后,分布可能会很不均匀,必然会造成个别节点处理的id数量远大于其他节点,这就起不到负载均衡的效果。这可以通过引入虚拟节点的方式解决,即对每一个节点计算多个HASH值,尽量保证这些HASH值比较均匀的分布在值空间中。当根据id查找节点时,找到的是虚拟节点,然后再根据虚拟节点查找对应的真实节点。多了一次查找的过程。如下图:
hash3

 

一致性hash算法提出了在动态变化的Cache环境中,判定哈希算法好坏的四个定义:
1、平衡性(Balance):平衡性是指哈希的结果能够尽可能分布到所有的缓存中去,这样可以使得所有的缓冲空间都得到利用。
2、单调性(Monotonicity):单调性是指如果已经有一些内容通过哈希分派到了相应的缓存中,又有新的缓存加入到系统中。哈希的结果应能够保证原有已分配的内容可以被映射到原有的或者新的缓存中去,而不会被映射到旧的缓存集合中的其他缓冲区。
3、分散性(Spread):在分布式环境中,终端有可能看不到所有的缓冲,而是只能看到其中的一部分。当终端希望通过哈希过程将内容映射到缓冲上时,由于不同终端所见的缓冲范围有可能不同,从而导致哈希的结果不一致,最终的结果是相同的内容被不同的终端映射到不同的缓冲区中。这种情况显然是应该避免的,因为它导致相同内容被存储到不同缓冲中去,降低了系统存储的效率。分散性的定义就是上述情况发生的严重程度。好的哈希算法应能够尽量避免不一致的情况发生,也就是尽量降低分散性。
4、负载(Load):负载问题实际上是从另一个角度看待分散性问题。既然不同的终端可能将相同的内容映射到不同的缓冲区中,那么对于一个特定的缓冲区而言,也可能被不同的用户映射为不同 的内容。与分散性一样,这种情况也是应当避免的,因此好的哈希算法应能够尽量降低缓冲的负荷。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值