redis的分片集群采用哈希的策略进行,由哈希值决定请求交予哪个具体的服务器处理。
假设有三台服务器,[0, 1, 2];使用哈希函数,例如取模,hash = key % 3;得到key的哈希值之后,将key发送到对应的服务器中处理。
由于key是完全无规律的,当其中一台服务器挂掉之后,hash变成hash = key%2;这样几乎所有key的哈希值都会改变,也就导致几乎所有key的缓存都失效了,造成缓存雪崩。
根本原因就是因为一个服务器宕机之后,哈希函数发生了变化(由之前的key%3变成了key%2),所以影响到了所有的key;
为了将服务器宕机导致的key失效的影响降到最低,我们需要尽量保证服务器宕机并不影响哈希函数,也就是将哈希函数固定,将哈希函数与服务器数量解耦。无论是一致性哈希还是redis分片集群采用的哈希槽,根本思想都是这个。
一致性哈希
一致性哈希固定一个数组的长度为2^32-1,hash函数为(key % 2^32
)。这个数组是环状的,2^32-1的下一个数字是0。所有的服务器被均匀的放在环上,当key得到一个hash值之后,就沿着顺时针方向寻找遇到的第一个服务器。
这样当一个服务器1宕机时,影响的只是原来从服务器0~服务器1之间的这部分数据,这部分数据被顺时针流向了服务器2;
但是当增加一台服务器时,带来的影响也变得有限。比如加了台服务器3,那么影响的只是服务器2~服务器3之间的这部分key。
为了解决这个问题,一致性哈希引入了虚拟节点。整个环上的节点都是虚拟节点,虚拟节点