目录
1、clusterState.slots和clusterNode.slots(记录槽位信息的结构体)
2、命令转发流程(寻找某槽位对应的节点)
3、重新指派(增加节点)
4、故障转移
1、clusterState.slots和clusterNode.slots(记录槽位信息的结构体)
每个节点内都有clusterState.slots和clusterNode.slots这俩结构,clusterState.slots和clusterNode.slots是必须都存在的:
(1)clusterState.slots用于花费O(1)的时间复杂度找到某个slot的处理节点。clusterState结构中的slots数组(clusterState.slots)记录了集群中所有16384个槽的指派信息,slots数组包含16383个项,每个数组项都指向一个clusterNode结构的指针,如果slots[i]指向null,表示i槽尚未指派给任何节点,否则指派给slots[i]指向的节点。【结构】每个项指向一个clusterNode结构的指针,如果为NULL表示还未分配,反之是一个clusterNode的话,就表示该槽已经分配。
(2)clusterNode.slots用于记录自己处理哪些槽,并向其他节点同步自己的负责信息。【结构】是一个二进制位数组(bit array),这个数组的长度为16348/8=2048个字节,共包含16384个二进制位,redis以0为起始索引,16384为终止索引,根据索引i上的二进制位的值来判断是否处理槽i:如果slots数组在索引i上的二进制位的值为1,那么表示节点负责处理槽i;如果slots数组在索引i上的二进制位的值为0,那么表示节点不负责处理槽i。
2、命令转发流程(寻找某槽位对应的节点)
客户端发送命令到某个节点,此节点根据key计算属于哪个槽,节点判断自己是否是负责处理这个槽的节点:
(1)是,处理命令
(2)不是,向客户端返回一个MOVED错误,指引客户端转向正确的节点(会将ip:port在MOVED错误中返回)。客户端接受到错误后会重新发送命令给重定向的节点。注意:集群模式下MOVED错误并不会被打印出来,而单机模式由于不知道该种错误类型会将它直接抛出。
3、重新指派(增加节点)
在三个节点的redis集群,当要给该集群在增加一个节点node4时,槽在已被全部分配,但是node4需要被分配一部分槽给他,不然node4相当于没有工作,所以需要重新分片。以node3需要把槽15000~16384重新分配给node4为例:
- 开始对15000槽重新分配。
- node4准备导入属于15000槽的键值对。
- node3准备迁移属于15000槽的键值对。
- 如果node3存在15000槽的键值对,将这些键值对导入node4。
- 将槽指派给node4,完成对15000槽的重新指派。
- 其他槽的重新指派重复以上步骤。
当15555槽正在从node3转移到node4时,会出现一种情况就是15555槽对应的键值对有一部分在node3,另一部分在node4。当客户端需要对15555槽下的一个键值对的更新时,node3会首先检查该键值对的key是否在当前节点,在就更新,不在返回ask错信信息,并指引客户端将该键值对写入node4。
4、故障转移
集群中的每个节点互相ping其他节点,当没有收到有效回复,就会认定其节点下线。当集群中有一半的节点认定该节点下线,就会广播一条消息告知全部节点,将该节点认定为下线状态,并开始故障转移。
故障转移步骤:
- 在下线主节点的所有从节点里面选择一个从节点。
- 被选中的从节点会执行SLAVEOF no one命令,成为新的主节点。
- 新的主节点会撤销所有对已下线主节点的槽指派,并将这些槽全部指派给自己。
- 新的主节点向集群广播一条PONG消息,这条PONG消息可以让集群中的其他节点立即知道这个节点已经由从节点变成了主节点,并且这个主节点已经接管了原本由已下线节点负责处理的槽。
- 新的主节点开始接收和自己负责处理的槽有关的命令请求,故障转移完成。