一致性哈希

背景这块就简单说一下,一致性哈希是为了解决简单哈希带来的问题。

以 redis 分布式缓存场景为例
有大概一百万张图片要分在 4 台机器上,后来数据量变多了,需要增加一台机器。

简单哈希

简单哈希的做法是,首先计算哈希值,然后进行取模运算
hash(图片名称) % N
那么每张图片都会对应到一台机器上,很好的解决了图片分散存储的问题。

但是,当我们需要增加一台服务器的时候就出问题了。 取模运算的结果不一样了,在对应的机器上找不到缓存,大量缓存在同一时间失效,造成了缓存的雪崩

为了解决这个问题,发明了一致性哈希算法。

一致性哈希

一致性哈希也是取模算法,但是不是对服务器数量,而是对 2^32 取模。
为什么是 2^32?
因为,java 中 int 的最大值是 2^31-1 最小值是-2^31,2^32 刚好是无符号整形的最大值;

简单来说,一致性 Hash 算法将整个哈希值空间组织成一个虚拟的圆环,假设某哈希函数 H 的值空间为 0 ~ 2^32-1(即哈希值是一个 32 位无符号整形)
哈希算法合理的话,图片应该是大致均匀分布在这个虚拟的圆环上。
hash(图片名称) % 2^32

同时服务器也需要进行哈希
hash(服务器A的IP地址) % 2^32

图片和服务器都哈希取模完后,就能确定此数据在环上的位置,从此位置沿环顺时针“行走”,第一台遇到的服务器就是其应该定位到的服务器

假设此时有 C 服务器发生故障,那么原 B~C 的数据会重新定位到 D 服务器,其他服务器的数据则不受影响。
增加一台一起也是一样,只有一部分内容会受到影响。具有较好的容错性和可扩展性。

一致性哈希的其他问题及解决方案

数据倾斜问题

数据倾斜问题指的是,当服务器进行哈希取模的时候,没有平均分配到数据环上。比如 ABCD 全都在右半区,那么 A 节点受到的压力会是最大的,其他节点受到的压力会小一些。
解决方案是 增加虚拟节点:
即 对每一个节点计算多个哈希值。
在实际应用中,通常将虚拟节点数设置为 32 甚至更大,因此即使很少的服务节点也能做到相对均匀的数据分布。

怎么计算出多个节点
Hash(192.168.1.1#1”); // cache A1
Hash(192.168.1.1#2”); // cache A2