系统设计面试:卷1 第五章:设计一致哈希 翻译

112 阅读8分钟

声明:仅以此文进行学习,如果翻译存在问题的话,请指正。 为了实现水平扩展,重要的是在服务器之间高效且均匀地分发请求/数据。一致散列是实现这一目标的常用技术。但首先,让我们深入了解一下这个问题。

Rehashing 问题

如果有n个缓存服务器,平衡负载的常用方法是使用以下哈希方法:serverIndex = hash(key) % n,其中n是服务器池的大小。

让我们用一个例子来说明它是如何工作的。如表5-1所示,我们有4个服务器和8个字符串键及其哈希值。

image.png 为了获取存储键的服务器,我们执行模块化操作f(key) % 4。例如,hash(key0) % 4 = 1表示客户端必须联系服务器1才能获取缓存的数据。

根据表5-1,key的分配如图5-1所示

image.png 当服务器池的大小固定且数据分布均匀时,这种方法可以很好地工作。但是,当添加新服务器或删除现有服务器时,就会出现问题。例如,如果服务器1脱机,则服务器池的大小变为3。使用相同的哈希函数,我们得到一个键相同的哈希值。但是应用模块化操作会得到不同的服务器索引,因为服务器的数量减少了1。我们应用hash (key)% 3得到的结果如表5-2所示:

image.png

根据表5-2,新的hashkey的分布如图5-2所示

image.png

如图5-2所示,大多数hashkey都被重新分配,而不仅仅是那些原本存储在脱机服务器(服务器1)上的hashkey。这意味着当服务器1脱机时,大多数缓存客户端将连接到错误的服务器来获取数据。这将导致大量缓存未命中。一致性hash是缓解此问题的有效技术。

一致性hash

引用自维基百科:“一致性哈希是一种特殊类型的哈希,当哈希表重新调整大小并使用一致性哈希时,平均只需要重新映射k/n个键,其中k是键的数量,n是槽的数量。相比之下,在大多数传统哈希表中,数组槽数的变化会导致几乎所有键都被重新映射[1]”。

hash槽与hash环

现在我们了解了一致哈希的定义,让我们来看看它是如何工作的。假设使用SHA-1作为哈希函数f,哈希函数的输出范围为:x0, x1, x2, x3,…,xn。在密码学中,SHA-1的哈希空间从0到2^160 -1。这意味着x0对应于0,xn对应于2^160 - 1,中间所有的哈希值都在0到2^160 - 1之间。哈希空间如图5-3所示。

image.png

将两端集合,得到一个哈希环,如图5-4所示: image.png

hash 服务器

使用相同的哈希函数f,我们根据服务器IP或名称将服务器映射到环上。

如图5-5所示,哈希环上映射了4个服务器

image.png

Hash Keys

值得一提的是,这里使用的哈希函数与“rehash问题”中的哈希函数不同,并且没有模块化操作。如图5-6所示,将4个缓存键(key0, key1, key2, key3)散列到哈希环上

image.png

Hash Key 映射

要确定key存储在哪个服务器上,我们从环上的key的位置顺时针进行,直到找到服务器。流程如图5-7所示。顺时针方向,key0存储在服务器0上;Key1存储在服务器1上;Key2存储在服务器2上,key3存储在服务器3上。

image.png

添加服务器

使用上面描述的逻辑,添加一个新服务器只需要重新分配一小部分key。

在图5-8中,新增服务器4后,只需要重新分配key0。K1、k2和k3仍然在相同的服务器上。让我们仔细看看其中的逻辑。在添加服务器4之前,key0存储在服务器0上。现在,key0将存储在服务器4上,因为服务器4是它从key0在环上的位置顺时针方向遇到的第一个服务器。其他键不基于一致散列算法重新分布。

image.png

移除服务器

当服务器被删除时,只有一小部分键需要使用一致的散列重新分配。在图5-9中,当服务器1被移除时,只有key1需要重新映射到服务器2。其余的key不受影响。

image.png

以上基本一致性hash存在的问题

一致性哈希算法是由MIT的Karger等人提出。其基本步骤是:

  • 使用统一分布的哈希函数将服务器和密钥映射到环上。

  • 要找出一个键映射到哪个服务器,从键位置顺时针走,直到找到环上的第一个服务器

这种方法存在两个问题。首先,考虑到可以添加或删除服务器,不可能为所有服务器保持相同大小的分区。分区是相邻服务器之间的哈希空间。分配给每个服务器的分区的大小可能非常小,也可能相当大。在图5-10中,如果s1被移除,s2的分区(用双向箭头突出)的大小是s0和s3的分区的两倍大小。

image.png

其次,环上可能存在不均匀的数据分布。例如,如果服务器映射到如图5-11所示的位置,则大多数密钥存储在服务器2上。但是,服务器1和服务器3上却没有数据

image.png

我们可以使用一种称为虚拟节点或副本的技术来解决这些问题。

虚拟节点

虚拟节点是指实节点,每个服务器由环上的多个虚拟节点表示。在图5-12中,服务器0和服务器1各有3个虚拟节点。3是任意选择的;而在现实世界的系统中,虚拟节点的数量要大得多。

我们不用s0,而是用s0_0、s0_1和s0_2表示环上的服务器0。类似地,s1_0、s1_1和s1_2表示环上的服务器1。对于虚拟节点,每个服务器负责多个分区。标签为s0的分区(边)由服务器0管理。

另一方面,标签为s1的分区由服务器1管理。

image.png

要查找当前key存储在哪个服务器上,我们从密钥的位置开始顺时针查找在环上遇到的第一个虚拟节点。在图5-13中,为了找出k0存储在哪个服务器上,我们从k0的位置顺时针方向找到虚拟节点s1_1,它指的是服务器1。通常我们可以使用一个hash表或简单的算法映射去寻找虚拟节点对应的实际服务器节点(感兴趣可以自行百度)。

image.png

随着虚拟节点数量的增加,密钥的分布变得更加平衡。

这是因为虚拟节点越多,标准差越小,从而使数据分布更加均衡。标准偏差衡量的是数据的分布情况。实验结果表明,在100个或200个虚拟节点的情况下,标准偏差在平均值的5%(200个虚拟节点)到10%(100个虚拟节点)之间。当我们增加虚拟节点的数量时,标准差会变小。但是,需要更多的空间来存储有关虚拟节点的数据。

这是一种权衡,我们可以调整虚拟节点的数量以适应我们的系统需求.

查找受到rehash影响的key

当添加或删除服务器时,需要重新分发一小部分数据。我们如何找到受影响的范围来重新分配键?如图5-14所示,服务器4加入到环中。受影响的范围从s4(新添加的节点)开始,沿环逆时针移动,直到找到服务器(s3)。因此,位于s3和s4之间的键需要重新分发到s4。

image.png

如图5-15所示,当一个服务器(s1)被移除时,受影响的范围从s1(被移除的节点)开始沿环逆时针移动,直到找到一个服务器(50)。因此,位于50和s1之间的键必须重新分配到s2。

image.png

总结

在本章中,我们深入讨论了一致性哈希,包括为什么需要它以及它是如何工作的。一致性哈希的好处包括:

  • 当添加或删除服务器时,最小化的键被重新分配。

  • 容易横向扩展,因为数据分布更均匀。

  • 可以缓解热点key问题。对特定分片的过度访问可能导致服务器过载。想象一下,凯蒂·佩里(Katy Perry)、贾斯汀·比伯(Justin Bieber)和Lady Gaga的数据最终都在同一个分片上。一致散列通过更均匀地分布数据来帮助缓解这个问题。

  • 对于虚拟节点的数量需要进行权衡调整,一致性hash算法如何进行映射也值得学习。

一致性哈希在现实世界的系统中得到了广泛的应用,包括一些值得注意的:

  • Amazon Dynamo数据库的分区组件
  • Apache Cassandra的跨集群数据分区
  • Discord聊天应用程序
  • Akamai内容分发网络
  • 磁悬浮网络负载平衡器 祝贺你走了这么远!现在给自己点鼓励吧。好工作!