一致性哈希

一致性哈希在哈希算法基础上, 适用于动态变化的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的配置也进行哈希运算。具体步骤如下:

  1. 先求出每个Cache的哈希值, 并将其配置到一个0~2^32的圆环区间上(为啥是32?哈希值一般不超过32位)
  2. 求出需要存储对象的哈希值, 也将其配置到这个圆环上
  3. 从对象所映射到的位置顺时针开始找, 把对象保存在第一个找到的Cache节点上

一致性哈希算法

新增Cache服务器的情景

假设在这个环形哈希空间中, Cache5被映射在Cache3和Cache4之间, 那么受影响的将仅是沿Cache5逆时针遍历, 直到下一个Cache(Cache3)之间的对象. 只对这些对象进行转移即可. Cache3~Cache5之间部分原来映射到Cache4, 现在应该映射到Cache5;
Cache5~Cache4之间部分原来映射到Cache4, 现在还是映射到Cache4, 不受影响;

新增Cache服务器的情景

删除Cache服务器的情景

假设在这个环形哈希空间中, Cache3被移除, 那么受影响的将仅是沿Cache3逆时针遍历直到下一个Cache(Cache2)之间的对象

原来Cache2~Cache3之间部分原来映射到Cache3, 现在应该映射到Cache4;
原来Cache3~Cache4之间部分原来映射到Cache4, 现在还是映射到Cache4, 不受影响;

删除Cache服务器的情景

虚拟Cache服务器

考虑到哈希算法并不是保证绝对的平衡, 尤其Cache较少的话, 对象并不能被均匀的映射到Cache上. 为了解决这种情况引入了”虚拟节点”的概念.
虚拟节点是实际节点在环形空间的复制品, 一个实际节点对应了若干个”虚拟节点”, 这个对应个数也称为”复制个数”, “虚拟节点”在哈希空间中以哈希值排列.

仍以4台Cache服务器为例,设置”复制个数”为2后, 共有8个“虚拟节点”分部在环形区域上, 会如下图一样:

虚拟节点

引入了”虚拟节点”后,映射关系就从对象-->Cache服务器转换成了对象-->虚拟节点-->Cache服务器. 当然虚拟节点与真正的服务器之间也有对应关系. 查询对象所在Cache服务器的映射关系整个流程如下图所示:

映射关系