设计一致性哈希系统

重新哈希的问题

如果有n个缓存服务器,常见的负载均衡方法是使用如下哈希方法

服务器序号= hash(key) % N (N 代表服务器池的大小)

这个方法在服务器池大小固定不变时效果很好,并且数据的分布是均匀的,但 当添加服务器或现有服务器被移除时问题就产生了。

N 变了,大部分的键都被重新分配了。一致性哈希是缓解这个问题的有效技术。

一致性哈希

定义,一致性哈希是一种特殊的哈希,如果一个哈希表被调整了大小,那么使用一致性哈希,则平均只需要重新映射 k/n 个键,k 是键的数量,n 是槽的数量。

大多数传统的哈希表中,只要槽的数量有变化,几乎所有的键都需要重新映射一遍。

哈希空间和哈希环

假设我们使用 SHA-1 作为哈希函数f, 哈希函数的输出值范围是 : xO, x 1, x2, x3, …, xn

在密码学里,SHA-1 的哈希空间是 0 到 2^160 - 1,这意味着 x0 对应 0,xn 对应 2^160 - 1

连接 x0 和 xn 两端,得到哈希环。

图5-4

哈希服务器

使用同样的哈希函数f,根据服务器的IP或者名字将其映射到哈希环上

图5-5

哈希键

这里使用哈希函数 没有求余运算,4个键 key0、key1、key2、key3 被映射到哈希环上。

图5-6

查找服务器

为了确定某个键存储在哪个服务器上,从这个键在环上的位置开始顺时针查找,直到找到一个服务器为止。

图5-7

添加服务器

按照上面描述的逻辑,如果在哈希环中添加一个新的服务器,只有少部分键需要被重新 映射到新的服务器,大部分键的位置保持不变。

图5-8

移除服务器

当一个服务器被移除时,如果使用一致性哈希,就只有一小部分键需要重新分配位置。

图5-9

两个问题

一致性哈希算法是MIT的 David Karger 等人首先提出的,基本步骤如下:

  1. 使用均匀分布的哈希函数将服务器和键映射到哈希环上
  2. 要找出某个键被映射到了哪个服务器上,就从这个键的位置开始顺时针查找,直到找到哈希环上的第一个服务器

两个问题:

一,考虑到可以添加或移除服务器,所以很难保证哈希环上所有服务器的分区大小相同。分区是相邻服务器之间的哈希空间。在哈希环上分配给每个服务器的分区可能很小,也可能很大

图5-10

二,有可能键在哈希环上是非均匀分布的

图5-11

虚拟节点

虚拟节点是实际节点在哈希环上的逻辑划分或映射,每个服务器都可以用多个虚拟节点来表示。

图5-12

为了找到某个键存储在哪个服务器上,从这个键所在的位置开始,顺时针找到第一个虚拟节点。

当虚拟节点的数量增加时,键的分布就会变得更均匀,这是因为有更多虚拟节点之后,标准差会变小, 从而导致数据分布更均匀。标准差衡量的是数据的分散程度。

图5-13

找到受影响的键

当添加或移除服务器时,有一部分键需要重新分配位置,如何找到受影响的键的范围并重新为它们分配位置呢?

从新添加的节点开始,沿着哈希环逆时针移动,直到遇到另一个服务器为止,就是受影响的键的范围。

图5-14

从被移除的节点开始,沿着哈希环逆时针移动,知道遇到另一个服务器为止,就是受影响的键的范围。

图5-15