若有收获,请记得分享和转发哦
我们都知道Redis的集群有三种方案:
1、主从复制模式
2、Sentinel(哨兵)模式
3、Redis Cluster模式
当然使用随着海量数据的存储要求,单台Redis配置有限,已经满足不了我们的需求。我们考虑采用分布式集群方案。
Redis Cluster 采用数据分片机制,定义了 16384个 Slot槽位,集群中的每个Redis 实例负责维护一部分槽以及槽所映射的键值数据。
客户端可以连接集群中任意一个Redis 实例,发送读写命令,如果当前Redis 实例收到不是自己负责的Slot的请求时,会将该slot所在的正确的Redis 实例地址返回给客户端。
客户端收到后,自动将原请求重新发到这个新地址,自动操作,外部透明。
CRC16的算法原理:
根据CRC16的标准选择初值CRCIn的值
将数据的第一个字节与CRCIn高8位异或
判断最高位,若该位为 0 左移一位,若为 1 左移一位再与多项式Hex码异或
重复3直至8位全部移位计算结束。
重复将所有输入数据操作完成以上步骤,所得16位数即16位CRC校验码。
CRC16 算法最大值
CRC16 算法,产生的hash值有 16 bit 位,可以产生 65536(2^16)个值 ,也就是说值分布在 0 ~ 65535 之间
这时候,疑问来了,槽位总数为什么是 16384 ?65536 不可以吗?
传输过程中,会对bitmap进行压缩,bitmap的填充率越低,压缩率越高。
bitmap 填充率 = slots / N (N表示节点数),
所以,插槽数偏低的话, 填充率会降低,压缩率会升高。
综合下来,从心跳包的大小、网络带宽、心跳并发、压缩率等维度考虑,16384 个插槽更有优势且能满足业务需求。
其中,消息头有一个myslots的char类型数组,unsigned char myslots[CLUSTER_SLOTS/8];,数组长度为 16384/8 = 2048 。底层存储其实是一个bitmap,每一个位代表一个槽,如果该位为1,表示这个槽是属于这个节点。
消息体中,会携带一定数量的其他节点信息用于交换,约为集群总节点数量的1/10,节点数量越多,消息体内容越大。10个节点的消息体大小约1kb。
划重点:
细心的同学可能会有疑问,char不是占2个字节吗?数组长度为什么是 16384/8?不应该是 16384/16 吗?
总结:
1、每秒 redis节点需要发送一定数量的ping消息作为心跳包,如果槽位为 65536,这个ping消息的消息头太大了,浪费带宽。
2、业务上看,集群主节点数量基本不可能超过1000个。集群节点越多,心跳包的消息体携带的数据越多。如果节点超过1000个,会导致网络拥堵。因此redis作者,不建议redis cluster节点数量超过1000个。
3、槽位越小,节点少的情况下,压缩率更高