Redis集群中分为主节点和从节点,主节点用于处理槽,从节点用于复制某个主节点,并在复制的主节点下线时,代替下线的主节点继续处理命令请求
设置从节点
执行CLUSTER REPLICATE <node_id>命令,可以让接收该命令的节点成为node_id的从节点,并开始对主节点进行复制
执行该命令的时候主要做了以下事情:
- 在自己的clusterState.nodes字典中找到node_id对应的clusterNode结构,并将自己的clusterState.myself.slaveof指针指向这个结构,表示自己称为了它的从节点
- 修改自己clusterState.flags属性,打开
REDIS_NODES_SLAVE标识,表示自己称为了从节点 - 向主节点发送
SLAVEOF命令开始复制主节点
说人话就是将节点标识成从节点,并且记录它的主节点是谁

一个节点成为从节点,并开始复制某个主节点这个信息会通过消息发送给集群中的其他节点,最终集群中所有的节点都会知道某个从节点正在复制某个主节点的
集群中所有节点都会在那一个主节点的clusterNode结构的slaves属性记录正在复制这个主节点的从节点名单

故障检测
集群中每个节点都会定期地向集群中的其他节点发送PING消息,以此来检测对方是否在线
如果接受PING消息的节点没有在规定时间内回复PONG消息,那么发送PING消息的节点就会将其标记位疑似下线(PFAIL)
如果集群中有半数以上的主节点都将某个主节点x标记为疑似下线,那么这个主节点就会被标记为下线(FAIL),并且将该主节点标记为下线的节点会向集群广播一条关于x的FAIL消息,所有接收到这条消息的节点(主节点或者从节点)会立马将主节点x标记为下线
关于PING、PONG消息
集群里的每个节点默认每隔一秒钟就会从已知节点列表中随机选出五个节点,然后对这五个节点中最长时间没有发送过PING消息的节点发送PING消息,以此来检测被选中的节点是否在线。
除此之外,如果节点A最后一次收到节点B发送的PONG消息的时间,距离当前时间已经超过了节点A的clusternodetimeout选项设置时长的一半,那么节点A也会向节点B发送PING消息,这可以防止节点A因为长时间没有随机选中节点B作为PING消息的发送对象而导致对节点B的信息更新滞后
故障转移
当一个从节点发现自己复制的主节点下线了,那么从节点开始进行故障转移:
- 下线主节点的从节点中,会有一个从节点会被选中
- 被选中的从节点会执行
SLAVEOF no one命令,称为新的主节点 - 新的主节点会撤销下线的主节点的槽指派,并将这些槽全部指派给自己
- 新的主节点向集群广播一条
PONG消息,让大家知道它已经替代成为了主节点
选举新的主节点
每个主节点都有一次投票的机会,第一次向主节点要求投票的从节点会获得主节点的投票
当从节点发现自己复制的主节点下线时,就会广播CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST消息,第一次收到该消息的主节点就会回复CLUSTER_TYPE_FAILOVER_AUTH_ACK消息,表示该主节点投票给它
从节点根据收到多少条CLUSTER_TYPE_FAILOVER_AUTH_ACK来判断自己获得了多少个主节点的支持
如果集群中有N个具有投票权的主节点,那么当一个从节点收集到大于等于(N/2+1)个支持时,这个从节点就会当选为新的主节点
如果没有选出主节点就会重新来一次
从节点需要大于等于(N/2+1)个支持才能成为主节点,这也说明Redis集群至少需要3个主节点
因为假设只有2个主节点,当一个节点下线进行故障转移时,由于只剩下1个具有投票权的主节点,而根据(N/2+1),从节点必须要获得2个主节点的支持才能成为新的主节点,这是无法满足的
参考
本文使用 mdnice 排版