redis集群

    科技2022-07-11  81

    1、节点

    一个节点就是一个运行在集群模式下的redis服务器; 集群数据结构 clusterNode: 每个节点都保存着一个clusterState结构,这个结构记录了在当前节点的视角下,集群目前所处的状态:集群是在线还是下线、集群包含多少个节点、集群当前的配置纪元; cluster meet指令的实现 假如向A发送这个命令。

    A为B创建一个clusterNode结构,将其添加到clusterState.nodes字典里面;A根据指令中给出的IP地址和端口号,向节点B发送一条meet消息;B为A创建一个clusterNode结构,将其添加到clusterState.nodes字典里面;B向A返回一条PONG消息;A收到B的PONG,可以知道B已经成功地接收到了自己的meet;A向B发送一条PING;B收到PING,表示A已经成功接收到了自己的PONG;

    2、槽指派

    集群的整个数据库被分为16384个槽,当每个槽都有节点在处理时,集群处于上线状态,否则处于下线状态;

    clusterNode的slots和numslot属性记录了节点负责处理哪些槽;

    一个节点除了会将自己负责的槽记录在slots和numslot里面,还会将自己的slots数组通过消息发送给集群的其他节点,以此告知其他节点自己目前负责处理的槽; 当A从B那里接收到B的slots数组后,A会在自己的clusterState.nodes字典中查找B对应的clusterNode结构,并对其slots数组进行更新; 集群中的每个节点都知道数据库的槽分别被指派给了哪些节点;

    clusterState.slots[16384]每一项都是一个指向clusterNode的指针;

    如果slots[i]为NULL,表示槽i尚未指派给任何节点;若是slots[i[指向一个clusterNode结构,表示槽i已经指派给了该节点;

    3、在集群中执行命令

    在对数据库中的16384个槽都进行了指派之后,集群进入上线状态,客户端就可以向集群中的节点发送数据命令了; 当客户端向节点发送与数据库键有关的命令时,接收命令的节点会计算出命令要处理的数据库键属于哪个槽,并检查这个槽是否属于自己:

    这个槽正好指派给了自己,节点直接指向命令;

    否则,节点会向客户端返回一个MOVED错误,指引redirect至正确的节点。

    计算出键所属的槽i之后,节点检查clusterState.slots[i]是否等于clusterState.myself;

    4、重新分片

    redis集群的重新分片操作可以将任意数量已经指派给某个节点的槽改为指派给另一个节点,相关槽所属的键值对也会从源节点被移动到目标节点; 重新分片操作可以在线进行,在重新分片过程中,集群不需要下线,且源节点和目标节点都可以处理命令请求;

    重新分片的实现原理 redis集群的重新分片操作是由redis的集群管理软件redis-trib负责的,redis提供了进行重新分片所需的所有命令,而redis-trib则通过向源节点和目标节点发送命令来进行重新分片操作。

    5、复制和故障转移

    redis集群中的节点分为主节点和从节点,主节点用于处理槽,从节点用于复制某个主节点,并在被复制的主节点下线时,代替主节点继续处理命令请求; 设置从节点 向一个节点发送命令: cluster replicate node_id 可以让接收命令的节点成为node_id所指定节点的从节点,并开始对主节点进行复制;

    接收到该命令的节点首先会在自己的clusterState.nodes字典中找到node_id所对应节点的clusterNode结构,并将自己的clusterState.myself.slaveof指针指向这个结构,以此记录这个节点正在复制的主节点;修改自己在clusterState.myself.flags中的属性,关闭REDIS_NODE_MASTER,打开REDIS_NODE_SLAVE标识,表示这个节点由原来的主节点变成了从节点;节点调用复制代码,对主节点进行复制。

    一个节点成为从节点,并开始复制某个主节点这一信息会通过消息发送给集群中的其他节点,最终集群中的所有节点都知道某个从节点正在复制某个主节点。

    故障检测

    集群中的每个节点都会定期地向集群中的其他节点发送PING消息,以此来检测对方是否在线,如果接收PING消息的节点没有在规定时间内返回PONG消息,则会被标记为疑似下线。

    集群中的各个节点会通过互相发送消息来交换集群中的各个节点的状态信息,例如某个节点是处于在线、疑似下线、还是已下线。

    如果在一个集群里面,半数以上负责处理槽的主节点都将某个主节点x报告为疑似下线,那么这个主节点x将被标记为已下线,将主节点x标记为已下线的节点会向集群广播一条关于主节点x的FAIL消息,所有收到这条消息的节点都会立刻键主节点x标记为已下线;

    故障转移

    当一个从节点发现自己正在复制的主节点进入了已下线状态时,从节点将开始对下线节点进行故障转移:

    选择一个从节点执行slaveof no one成为新的主节点;新的主节点撤销所有对已下线主节点的槽指派,将这些槽全部指派给自己;新的主节点向集群广播一条PONG消息,这条PONG消息可以让集群中的其他节点立即知道这个节点已经由从节点变成了主节点,并且这个主节点已经接管了原本由已下线节点负责的槽;

    选举新的主节点

    集群的配置纪元是一个自增计数器,初始值为0;当集群中的某个节点开始依一次故障转移时,集群配置纪元的值会被增1;对于每个配置纪元,集群中每个负责处理槽的主节点都有一次投票的机会,而第一个向主节点要求投票的从节点将获得主节点的投票;当从节点发现自己正在复制的主节点进入已下线状态时,从节点会向集群广播一条CLUSTERMSG_FAILOVER_REQUEST消息,要求所有收到这条消息、且具有投票权的主节点向这个从节点投票;如果一个主节点具有投票权(正在负责处理槽),且尚未投票给其他从节点,那么主节点将向要求投票的从节点返回一条CLUSTER_TYPE_FAILOVER_AUTH_ACK消息,表示该主节点支持从节点成为新的主节点;每个参与选举的从节点根据自己收到了多少条这种消息来统计自己获得了多少主节点的支持;如果集群中有N个具有投票权的主节点,当一个从节点收集到大于等于N/2+1张(确保了新的主节点只会有一个)支持票时,这个从节点就会当选为新的主节点;如果在一个配置纪元中没有从节点能收集到足够多的支持票,那么集群进入一个新的配置纪元,并再次进行选举直到选出新的主节点为止;

    7、总结

    节点通过握手来将其他节点添加到自己所处理的集群当中;集群中的16384个槽可以分别指派给集群中的各个节点,每个节点都会记录哪些槽指派给了自己,而哪些槽被指派给了其他节点;节点接到一个命令请求时,会先检查这个命令请求要处理的键所在的槽是否由自己负责;重新分片的关键是将属于某个槽的所有键值对从一个节点转移至另一个节点;如果A正在迁移槽i至节点B,那么当A没能在自己的数据库中找到命令指定的数据库键时,A会向客户端返回一个ASK错误,指引客户端到B继续查找;MOVED错误表示槽的负责权已经从一个节点转移到了另一个节点,而ASK错误只是两个节点在迁移槽的过程中使用的一种临时措施;集群中的从节点用于复制主节点,并在主节点下线时,代替主节点继续处理命令请求;集群中的节点通过发送和接收消息来进行通信;
    Processed: 0.010, SQL: 8