为什么 Redis Cluster 是16384个槽位

为什么 Redis Cluster 是16384个槽位

    Redis集群通过分片的方式来保存数据库中的键值对:集群的整个数据库被分为16384个槽(slot),数据库中的每个键都属于这16384个槽的其中一个,集群中的每个节点可以处理0个或最多16384个槽。

   那么为什么被分为16384个槽?我们从以下各个维度来进行分析

    1.  插槽

    在Redis的集群中,每个插槽的状态信息需要进行记录以维护槽位的分配情况。这些状态信息通常使用位图来表示,其中每个插槽对应一个位,用于表示该插槽的状态。每个位只占用一个比特(bit),因此需要将插槽数除以8,将位的数量转换为字节(byte)的数量,以计算所需的空间大小。

    因此,如果有16384个插槽,则需要占用16384个比特,即16384 / 8 = 2048字节,即2KB的空间。同理,如果有65536个插槽,则需要65536 / 8 = 8192字节,即8KB的空间。

    clusterNode结构的slots 属性和numslot 属性记录了节点负责处理哪些槽:

 1 struct clusterNode{
 2 
 3      //...
 4 
 5      unsigned char slots[16384/8];
 6 
 7      int numslots;
 8 
 9      //...
10 
11 };

   slots是一个二进制数组,数组的长度16384/8=2048个字节=2KB。

   Redis以0为起始索引,16383为终止索引,对slots数组中的16384个二进制位进行编号,并根据索引 i 上的二进制为的值来判断节点是否负责处理槽 i :

  •    如果slots数组在索引i上的二进制位的值为1,那么表示节点负责处理槽i。
  •    如果slots 数组在索引i上的二进制位的值为0,那么表示节点不负责处理槽i。

   下图展示了一个slots数组示例∶这个数组索引0至索引7上的二进制位的值都为1,其余所有二进制位的值都为0,这表示节点负责处理槽0至槽7。

    

 

    2.  槽与集群节点

    当集群中新增或移除节点时,槽的分配会自动进行重新平衡,以确保每个主节点负责的槽数量大致相等。这样可以保证数据在集群中均匀分布,避免了数据倾斜的问题。

    因此,槽与集群节点之间的关系是通过槽的分配来确定的,每个主节点负责处理一部分槽的数据。当集群扩展到1000个节点时,每个主节点仍然负责处理大约16384 / 1000 ≈ 16个槽,这样即使在较大规模的集群中也能够保持数据分片的均匀性。

     Redis Cluster 不太可能扩展到超过 1000 个主节点,太多可能导致网络拥堵。

    16384 个插槽范围比较合适,当集群扩展到1000个节点时,也能确保每个master节点有足够的插槽。

    3.  心跳数据包大小以及网络带宽

    Redis每秒都会发送一定数量的心跳包,正常的心跳数据包携带节点的完整配置,它能以幂等方式来更新配置。如果采用 16384 个插槽,占空间 2KB (16384/8);如果采用 65536 个插槽,占空间 8KB (65536/8),未免有些太大了,浪费网络资源。

   上面提过,Redis的集群主节点数量一般不会超过1000个。集群中节点越多,心跳包的消息体内的数据就越多,如果节点过多,也会造成网络拥堵。因此Redis的作者不建议Redis Cluster的节点超过1000个,对于节点数在1000个以内的Redis Cluster,16384个槽位完全够用。

    4.  压缩位图以减少网络流量

   Redis主节点的哈希槽信息是通过bitmap存储的,在传输过程中,会对bitmap进行压缩,bitmap的填充率越低,压缩率越高。

   bitmap 填充率 = slots / N (N表示节点数)。

   也就是说slots越小,填充率就会越小,压缩率就会越高,传输效率就会越高

   综合下来,从心跳包的大小、网络带宽、心跳并发、压缩率等维度考虑,16384 个插槽更有优势且能满足业务需求。

posted @ 2024-01-27 09:35  欢乐豆123  阅读(455)  评论(0编辑  收藏  举报