背景

假设,我们有三台缓存服务器,用于缓存图片,我们为这三台缓存服务器编号为0号、1号、2号,现在,有3万张图片需要缓存,我们希望这些图片被均匀的缓存到这3台服务器上,以便它们能够分摊缓存的压力。假设图片名称是不重复的。

普通hash解决方案:

我们使用图片名称作为访问图片的key,,那么,我们可以使用如下公式,计算出图片应该存放在哪台服务器上。
hash(图片名称)% N
因为图片的名称是不重复的,所以,当我们对同一个图片名称做相同的哈希计算时,得出的结果应该是不变的,如果我们有3台服务器,使用哈希后的结果对3求余,那么余数一定是0、1或者2,对应到三台服务器上。

问题:

当3台缓存服务器已经不能满足我们的缓存需求,需要扩容,或者3号服务器故障不可用,会造成缓存的分布不均匀。

一致性哈希

一致性哈希算法也是使用取模的方法,只是,刚才描述的取模法是对服务器的数量进行取模,而一致性哈希算法是对2^32取模
image.png
圆环的正上方的点代表0,0点右侧的第一个点代表1,以此类推,2、3、4、5、6……直到2^32-1,也就是说0点左侧的第一个点代表2^32-1
我们把这个由2的32次方个点组成的圆环称为hash环

实现

假设我们有3台缓存服务器,服务器A、服务器B、服务器C,那么,在生产环境中,这三台服务器肯定有自己的IP地址,我们使用它们各自的IP地址进行哈希计算,使用哈希后的结果对2^32取模,可以使用如下公式示意。
hash(服务器A的IP地址) % 2^32
通过上述公式算出的结果一定是一个0到2^32-1之间的一个整数,我们就用算出的这个整数,代表服务器A,既然这个整数肯定处于0到2^32-1之间,那么,上图中的hash环上必定有一个点与这个整数对应,而我们刚才已经说明,使用这个整数代表服务器A,B,C,那么,服务器就可以映射到这个环上,用下图示意
image.png
而映射的图片号码获取公式
hash(图片名称) % 2^32
图片1,2,3,4映射到哈希环上
image.png

场景

当摘除服务器B
image.png

问题

实际的映射中,服务器可能会被映射成如下模样,不够均匀
image.png

引入虚拟节点

image.png

实际应用场景

redis集群使用的就是一致性哈希,有 2 ** 16(65536)个哈希槽