53d1b67a6480b444c008538e1ae89fd1.png

在很多集群架构中,为了保证集群数据的一致性,都会使用一致性哈希算法,因为一致性哈希算法,可以保证无论是增加节点,还是减少节点,被影响的数据都是一小部分数据。

不过,Redis集群例外,Redis 集群没有使用一致性哈希,取而代之的是引入了哈希槽的概念。哈希槽是Redis真正保存数据的地方。

3f09497a50685bcacd2105bf2bdb25c6.png

Redis 集群有16384个哈希槽,每个要保存到Redis的键值对,都会先通过CRC16函数计算,然后再对16384取模,来决定这个键值对要被放置哪个槽。

集群的每个节点都会负责一部分哈希槽,举个例子,如果当前集群有3个节点M1、M2、M3,那么:

  • 节点 M1可能 包含 0 到 5500号哈希槽
  • 节点 M2可能 包含5501 到 11000 号哈希槽
  • 节点 M3可能包含11001 到 16384号哈希槽

由于,Redis集群始终包含16384个哈希操作,因此,它很容易添加或者删除节点。比如,如果我想新添加个节点M4,那我只需要从节点 M1,M2,M3中得到部分槽,然后迁移到M4上即可。

307acc2ab53cc01fd94341997a745669.png

或者,如果我想移除节点M4,那我们只需要将M4中的槽移到M1、M2和M3节点上,最后将没有任何槽的M4节点从集群中移除即可。

18fbe53d629bce48abf830643a259fe6.png

由于从一个节点将哈希槽移动到另一个节点并不会停止服务,所以,无论添加、删除或者改变某个节点的哈希槽数量,都不会造成集群不可用的状态。

在前面的内容中,我们已经介绍过,存入到Redis集群中的每个Key是通过CRC16函数计算后取模再映射到不同的哈希槽中的,但CRC16函数的结果是一个16bit的数,也就是说它的最大值是2**16=65536。但Redis集群为什么仅有16384个哈希槽?

有以下几个原因。

在Redis集群中,每个节点每秒都会向集群中其他节点发送 ping 消息,以检测其它节点的状态。

在消息头中,最占空间的是保存哈希槽位置的bitmap大小。Bitmap的每一个位代表一个槽,如果该位为1,则表示这个槽是属于这个节点的。所以如果哈希槽总数设置为65536,那这个bitmap的大小最大将达到65536/(8*1024)= 8k,有点大。

另外,消息体中还会携带有约为集群总节点数量的1/10(至少携带3个)的节点的信息。这样节点数量越多,消息体内容越大。

所以,为降低由于消息过大而造成的通信阻塞影响,Redis的作者将Redis的节点数限制在1000,将哈希槽数限制在16384。

ad729c17eb1e2c9fdad6ccf134c8bb8f.png
Logo

开源、云原生的融合云平台

更多推荐