一致性哈希
一致性哈希在哈希算法基础上, 适用于动态变化的Cache环境中
场景
如果我们有4台Cache服务器来存放一些对象, 可以用简单的办法来分配:object.hashCode() % 4
.
- Cache0:
object.hashCode() % 4 == 0
- Cache1:
object.hashCode() % 4 == 1
- Cache2:
object.hashCode() % 4 == 2
- Cache3:
object.hashCode() % 4 == 3
动态变化体现在, 如果因为某些原因Cache服务器少了一台或者多了一台, 我们怎么处理对象与服务器的关系呢?
少了一台应该%3
, 多了一台应该%5
, 这样服务器上原来存放的对象与服务器的对应关系就全乱了
使用一致性哈希解决上述场景
算法步骤
一致性哈希算法采用一种新的方式来解决问题,不再仅仅依赖object.hashCode()本身,而且将Cache的配置也进行哈希运算。具体步骤如下:
- 先求出每个Cache的哈希值, 并将其配置到一个0~2^32的圆环区间上(为啥是32?哈希值一般不超过32位)
- 求出需要存储对象的哈希值, 也将其配置到这个圆环上
- 从对象所映射到的位置顺时针开始找, 把对象保存在第一个找到的Cache节点上
![一致性哈希算法](/assets/hash01-BDDtPLP8.png)
新增Cache服务器的情景
假设在这个环形哈希空间中, Cache5被映射在Cache3和Cache4之间, 那么受影响的将仅是沿Cache5逆时针遍历, 直到下一个Cache(Cache3)之间的对象. 只对这些对象进行转移即可. Cache3~Cache5之间部分原来映射到Cache4, 现在应该映射到Cache5;
Cache5~Cache4之间部分原来映射到Cache4, 现在还是映射到Cache4, 不受影响;
![新增Cache服务器的情景](/assets/hash02-BTxHfD0I.png)
删除Cache服务器的情景
假设在这个环形哈希空间中, Cache3被移除, 那么受影响的将仅是沿Cache3逆时针遍历直到下一个Cache(Cache2)之间的对象
原来Cache2~Cache3之间部分原来映射到Cache3, 现在应该映射到Cache4;
原来Cache3~Cache4之间部分原来映射到Cache4, 现在还是映射到Cache4, 不受影响;
![删除Cache服务器的情景](/assets/hash03-DPXN-tDV.png)
虚拟Cache服务器
考虑到哈希算法并不是保证绝对的平衡, 尤其Cache较少的话, 对象并不能被均匀的映射到Cache上. 为了解决这种情况引入了"虚拟节点"的概念.
虚拟节点是实际节点在环形空间的复制品, 一个实际节点对应了若干个"虚拟节点", 这个对应个数也称为"复制个数", "虚拟节点"在哈希空间中以哈希值排列.
仍以4台Cache服务器为例,设置"复制个数"为2后, 共有8个“虚拟节点”分部在环形区域上, 会如下图一样:
![虚拟节点](/assets/hash04-BbkjVVgu.png)
引入了"虚拟节点"后,映射关系就从对象-->Cache服务器
转换成了对象-->虚拟节点-->Cache服务器
. 当然虚拟节点与真正的服务器之间也有对应关系. 查询对象所在Cache服务器的映射关系整个流程如下图所示:
![映射关系](/assets/hash05-DlKbxYYb.png)