Redis集群槽位定位原理
上一节搭建了redis集群,现在要往集群中存储数据,那么集群是如何存储数据的呢?
实际上Cluster默认会对key做crc16算法的hash运算得到一个整数,然后拿这个整数值对16384进行取模得到具体的槽位。
HASH_SLOT = CRC16(key) mod 16384
Redise Cluster(集群)将所有数据划分为16384个slot(槽位),key经过hash运算得到的槽位值,就会将key往对应的槽位里面放。而Redis Cluster的Master节点会对16384个槽位进行划分,只有Master节点能够划分槽位如:
8001端口的master分配的槽位:0~5000
8002端口的master分配的槽位:5001~10000
8003端口的master分配的槽位:10001~16383
集群的配置信息也可以查到每个master所分配的槽位:
客户端数据经过key的hash运算就会知道往哪台redis节点放,也知道往哪台redis节点取。
当 Redis Cluster 的客户端来连接集群时,它也会得到一份集群的槽位配置信息并将其缓存在客户端本地。这样当客户端要查找某个 key 时,可以直接定位到目标节点。同时因为槽位的信息可能会存在客户端与服务器不一致的情况,还需要纠正机制来实现槽位信息的校验调整。
Redis集群节点间的通信机制
redis cluster节点间采取gossip协议进行通信。
gossip协议包含多种消息,包括ping,pong,meet,fail等等。ping
:每个节点都会频繁给其他节点发送ping,其中包含自己的状态还有自己维护的集群元数据,互相通过ping交换元数据;pong
: 返回ping和meet,包含自己的状态和其他信息,也可以用于信息广播和更新;fail
: 某个节点判断另一个节点fail之后,就发送fail给其他节点,通知其他节点,指定的节点宕机了。meet
:某个节点发送meet给新加入的节点,让新节点加入集群中,然后新节点就会开始与其他节点进行通信。
- 10000端口
每个节点都有一个专门用于节点间通信的端口,就是自己提供服务的端口号+10000,比如7001,那么用于节点间通信 的就是17001端口。 每个节点每隔一段时间都会往另外几个节点发送ping消息,同时其他几点接收到ping消息之后返 回pong消息。
Redis集群选举原理
Redis可以投票的成员是其他没挂Master节点。
当slave发现自己的master变为FAIL状态时,便尝试进行Failover,以期成为新的master。由于挂掉的master可能会有 多个slave,从而存在多个slave竞争成为master节点的过程, 其过程如下:
1.slave发现自己的master变为FAIL
2.将自己记录的集群currentEpoch(投票周期)加1,并广播FAILOVER_AUTH_REQUEST 信息
3.其他节点收到该信息,只有master响应,判断请求者的合法性,并发送FAILOVER_AUTH_ACK,对每一轮周期只发 送一次ack
4.尝试failover的slave收集master返回的FAILOVER_AUTH_ACK
5.slave收到超过半数master的ack后变成新Master(这里解释了集群为什么至少需要三个主节点,如果只有两个,当其 中一个挂了,只剩一个主节点是不能选举成功的)
6.广播Pong消息通知其他集群节点。
从节点并不是在主节点一进入 FAIL 状态就马上尝试发起选举,而是有一定延迟,一定的延迟确保我们等待FAIL状态在 集群中传播,slave如果立即尝试选举,其它masters或许尚未意识到FAIL状态,可能会拒绝投票
- 延迟计算公式: DELAY = 500ms + random(0 ~ 500ms) + SLAVE_RANK * 1000ms
SLAVE_RANK表示此slave已经从master复制数据的总量的rank。Rank越小代表已复制的数据越新。这种方式下,持有最新数据的slave将会越早发送FAILOVER_AUTH_REQUEST信息,越有可能成为新的节点。
Redis集群为什么至少需要三个master节点,并且推荐节点数为奇数?
因为新master的选举需要大于半数的集群master节点同意才能选举成功,如果只有两个master节点,当其中一个挂 了,是达不到选举新master的条件的。
奇数个master节点可以在满足选举该条件的基础上节省一个节点,比如三个master节点和四个master节点的集群相比,大家如果都挂了一个master节点都能选举新master节点,如果都挂了两个master节点都没法选举新master节点了,所以奇数的master节点更多的是从节省机器资源角度出发说的。