概述
集群结构:多个节点,单个节点主从结构,单个节点只存储部分键信息,多个节点作为整体提供服务
键分配
槽
集群整体被分为16384个槽,每个节点负责被指派处理的部分槽,所有槽都被指派以后,集群才能work
槽与键的关系
每个键都对应一个槽,CRC16(key) & 16383的结果就是槽号:key的CRC-16校验和,用位运算处理到0~16383之间
槽指派信息存储
ClusterNode:单个节点信息的数据结构,ClusterState:ClusterNode包含的该节点视角下的集群信息
ClusterNode.char slots[16384/8],二进制位数组,16384个槽,如果某个槽是由该节点处理,那么slots数组该槽对应的位值为1,否则为0
ClusterState.ClusterNode *slots[16384],每个节点的集群视角都会存储全局的每个槽对应的负责处理该槽的节点
ClusterState.zskiplist *slots_to_keys, 每个节点集群视角用跳跃表存储了全局某个槽对应的所有key,跳跃表中每个节点的分值存储的是槽号
集群构建
CLUSTER MEET MEET:A节点向B节点发送MEET消息 PONG:B节点接收MEET请求,响应PONG消息 PING:A接收到B响应的PONG消息,确认B节点已经成功接收MEET消息,A节点接着发送PING消息 握手完成:B接收到A的PING消息以后,确认A节点已经成功接收PONG消息,握手完成,B节点成功加入集群,并且AB都会维护对方的节点信息 CLUSTER REPLICATE <node_id> 该命令会将目标节点设置为node_id指定节点的从节点 主从结构也是由集群来维护的
集群信息同步-Gossip协议
Gossip协议是一种最终一致性协议,Redis实现了Gossip协议以达到每个节点视角的集群全局信息的最终一致性 具体实现:每次发送MEET、PING、PONG消息时,发送者都会从自己的已知节点列表中随机挑选两个(可以是主节点也可以是从节点)放到消息体中,接收者刷新对这两个节点的认知
集群故障转移
故障检测
PING消息在线检测,如果没有在规定时间响应PONG,进入疑似下线(PFAIL)状态 被半数以上的主节点标记为疑似下线状态(PFAIL),将被标记为下线状态
选举新主
整体过程类似领头Sentinel选举过程,都是基于raft算法的领头选举方法来实现 发起投票的是发起者为发现自己复制的主节点被标记为已下线状态的所有子节点 参与投票的为集群中的主节点 选举整体过程略
故障转移
被选举成新主的从节点,会负责进行故障转移工作
集群消息总结
MEET:请求接收者加入集群
PING:每个节点默认每隔一秒钟,从已知节点列表中随机选出五个节点,然后对这五个节点中最长时间没有发送过PING消息的节点发送PING消息,以检测被选中的节点是否在线;如果节点A最后一次收到节点B的PONG消息已经超过了cluster-node-timeout选项设置时间的一半,那么节点A也会向B节点发送PING消息
PONG:响应MEET、PING,反馈消息已达;另外,一个节点也可以广播PONG消息,让集群其它节点立即刷新关于这个节点的认知,例如当一次故障转移操作成功之后,新的主节点会向集群广播一条PONG消息
FAIL:如果一个节点A判断节点B进入FAIL状态,A会向集群广播一条关于B的FAIL消息,所有收到FAIL消息的节点会立即将B标记为已下线
PUBLISH:当一个节点收到一个PUBLISH命令时,节点会执行这个命令,并向集群广播一条PUBLISH消息,所有收到这条PUBLISH消息的节点都会执行相同的PUBLISH命令




