1. 哈希算法
想象我们的网络世界是一个巨大的环形摩天轮,上面有无数的座位,每个座位都代表了一个存储空间。现在,我们需要将三万张照片安排到这个摩天轮的三台机器上。这些机器我们可以想象成三个大车厢,每个车厢可以装载一部分照片。
在简单的哈希算法中,我们通过计算每张照片的哈希值来决定它应该放在哪个车厢。但如果我们决定在摩天轮上增加一个新的车厢,这时问题就来了。原本均匀分布的照片因为新车厢的加入,许多照片需要被重新分配到不同的车厢中,这就像是你已经坐好了,突然被告知要换一个座位,造成了大混乱。
(如果有三万张图片需要缓存到三台机器上,保证均匀分布,那么可以使用哈希算法来进行。通过对 key 值变为 hash 值后,取机器数余数,如图中所示,机器数量为 3,则可以保证在 key 一致的情况下,再次寻找该图片时可以找到对应的服务器上。
但是这种情况下有一种缺点,就是如果我们新增一台服务器,服务器数量由3 变为 4后,那么在相同 key 的情况下,取得的余数不同,例如
5 余 3 = 2 (存放到服务器 2)
5 余 4 = 1(存放到服务器 1)
导致无法找到对应的图片,缓存失效,客户端会向后端请求,导致后端雪崩。
这里需要注意的是,所有的图片的地址都发生了错误。)
2. 一致性哈希算法
那么为了解决这个问题,就要使用一致性哈希算法。
一致性哈希算法将哈希值组织在一个环形结构中,所有的服务器和数据项都映射到这个环上。哈希函数的选择需要保证均匀性,避免哈希碰撞。对于每一个数据项,通过其键值计算哈希值,然后沿环顺时针查找,将数据项分配到遇到的第一个服务器上。这保证了数据分布的均匀性和平衡性。为了进一步优化负载均衡,每个实际服务器可以在哈希环上分配多个虚拟节点。这样做可以在物理服务器较少时,通过增加虚拟节点的数量来模拟大规模分布式环境,从而优化数据的均匀分布。
有一个环为 2 的 32 次方,把服务器 ABC的哈希值取 2 的 32 次方的余数,那么结果必然会分布在这个圆环上,同时对想要存放的图片 a 的哈希值取余数,那么 a 也会在这个圆环上,这是如果要想知道 a 应该被存放在哪一台服务器,顺时针寻找服务器,那么找到的第一个服务器就是 a 应该被存放的服务器。
本图中,a 应该被存在 B服务器中。
那么,如果新增一台服务器 D,那么本来应该存放在 A 中都图片 c 就会被存放在 D 中,所以我们需要知道的是, 一致性哈希算法并不能解决所有的问题,仍会导致部分失效。但这样仍然比哈希算法好太多了。
我们可以推断出来,想让一致性哈希算法失效的情况减少,本质上减少每个服务器之间的间隔就好,就是服务器越多,失效的可能性越小。
想象一个极端情况,如果服务器 ABC 离的很近,同样也会导致大量的缓存失效。
但是如果我们只有三台服务器应该怎么办呢。答案是设置虚拟节点,一台服务器 A 可以对应虚拟节点 A1,A2,A3......这样,当图片遇到 A1时,就被存储到 A 中,每个服务器的间隔变小,实现了准确率较高的一致性哈希算法。
2. 参考
好刚: 7分钟视频详解一致性hash 算法
【好刚: 7分钟视频详解一致性hash 算法】 https://www.bilibili.com/video/BV1Hs411j73w/?share_source=copy_web&vd_source=94e7fb54e1e56a78eb4917d7e5240a87