我们都知道,对于客户端请求的key,redis是根据公式 HASH_SLOT=CRC16(key) mod 16384
,计算出映射到哪个分片上,然后Redis会去相应的节点进行操作。
CRC16
算法产生的hash值有16bit,该算法可以产生65536(2^16)个值。换句话说,值是分布在0~65535之间。那作者在做mod
运算的时候,为什么不mod
65536,而选择mod
16384?这个问题,作者是给出了回答的,详见: https://github.com/antirez/redis/issues/2576,下面我们来具体的讲一下。
1. 如果槽位为65536,发送心跳信息的消息头达8k,发送的心跳包过于庞大。
redis集群的节点之间会定期发送ping/pong消息,交换数据信息的,交换的数据信息,由消息体和消息头组成。
消息体无外乎是一些节点标识,IP,端口号,发送时间等等,这里我们主要关注的是消息头:
可以看到有个字段名为 myslots 的char数组,长度为 CLUSTER_SLOTS/8,CLUSTER_SLOTS为常量16384,所以该数组长度为16384/8,这其实是一个bitmap,每一个位代表一个槽,如果该位为1,表示这个槽是属于这个节点的。
该数组所占空间大小为 16384÷8÷1024=2kb,当槽位为65536时,这块的大小是: 65536÷8÷1024=8kb
。消息体中会携带一定数量的其他节点的信息,节点信息里同样包含其槽位信息,节点数大约占集群节点总数量的十分之一,至少是3个节点的信息。节点数量越多,消息体内容越大。
因为每秒钟,redis节点需要发送一定数量的ping消息作为心跳包,如果槽位为65536,这个ping消息的消息头太大了,浪费带宽。
2. redis的集群主节点数量基本不可能超过1000个
如上所述,集群节点越多,心跳包的消息体内携带的数据越多。如果节点过1000个,也会导致网络拥堵。因此redis作者,不建议redis cluster节点数量超过1000个。
3. 槽位越小,节点少的情况下,压缩率高
Redis主节点的配置信息中,它所负责的哈希槽是通过一张bitmap的形式来保存的,在传输过程中,会对bitmap进行压缩,但是如果bitmap的填充率slots / N很高的话(N表示节点数),bitmap的压缩率就很低。 如果节点数很少,而哈希槽数量很多的话,bitmap的压缩率就很低。
综上所述,作者决定取16384个槽,不多不少,刚刚好!