节点失效检测
以下是节点失效检查的实现方法:
- 当一个节点向另一个节点发送 PING 命令, 但是目标节点未能在给定的时限内返回 PING 命令的回复时, 那么发送命令的节点会将目标节点标记为 PFAIL (possible failure,可能已失效)。
- 等待 PING 命令回复的时限称为“节点超时时限(node timeout)”,是一个节点选项(node-wise setting)。
- 每次当节点对其他节点发送 PING 命令的时候, 它都会随机地广播三个它所知道的节点的信息, 这些信息里面的其中一项就是说明节点是否已经被标记为 PFAIL 或者 FAIL 。
- 当节点接收到其他节点发来的信息时, 它会记下那些被其他节点标记为失效的节点。 这称为失效报告(failure report)。
- 如果节点已经将某个节点标记为 PFAIL , 并且根据节点所收到的失效报告显式, 集群中的大部分其他主节点也认为那个节点进入了失效状态, 那么节点会将那个失效节点的状态标记为 FAIL 。
- 一旦某个节点被标记为 FAIL , 关于这个节点已失效的信息就会被广播到整个集群, 所有接收到这条信息的节点都会将失效节点标记为 FAIL 。
简单来说,一个节点要将另一个节点标记为失效,必须先询问其他节点的意见,并且得到大部分主节点的同意才行。
因为过期的失效报告会被移除,所以主节点要将某个节点标记为 FAIL 的话,必须以最近接收到的失效报告作为根据。
在以下两种情况中,节点的 FAIL 状态会被移除:
- 如果被标记为 FAIL 的是从节点, 那么当这个节点重新上线时, FAIL 标记就会被移除。
- 保持(retaning)从节点的 FAIL 状态是没有意义的,因为它不处理任何槽,一个从节点是否处于 FAIL 状态,决定了这个从节点在有需要时能否被提升为主节点。
- 如果一个主节点被打上 FAIL 标记之后, 经过了节点超时时限的四倍时间, 再加上十秒钟之后, 针对这个主节点的槽的故障转移操作仍未完成, 并且这个主节点已经重新上线的话, 那么移除对这个节点的 FAIL 标记。
在第二种情况中,如果故障转移未能顺利完成,并且主节点重新上线,那么集群就继续使用原来的主节点,从而免去管理员介入的必要。
集群状态检测(已部分实现)
每当集群发生配置变化时(可能是哈希槽更新,也可能是某个节点进入失效状态),集群中的每个节点都会对它所知道的节点进行扫描(scan)。
一旦配置处理完毕,集群会进入以下两种状态的其中一种:
- FAIL : 集群不能正常工作。 当集群中有某个节点进入失效状态时, 集群不能处理任何命令请求, 对于每个命令请求, 集群节点都返回错误回复。
- OK : 集群可以正常工作, 负责处理全部 16384 个槽的节点中, 没有一个节点被标记为 FAIL 状态。
这说明即使集群中只有一部分哈希槽不能正常使用,整个集群也会停止处理任何命令。
不过节点从出现问题到被标记为 FAIL 状态的这段时间里,集群仍然会正常运作,所以集群在某些时候,仍然有可能只能处理针对16384 个槽的其中一个子集的命令请求。
以下是集群进入 FAIL 状态的两种情况:
- 至少有一个哈希槽不可用,因为负责处理这个槽的节点进入了 FAIL 状态。
- 集群中的大部分主节点都进入下线状态。当大部分主节点都进入 PFAIL 状态时,集群也会进入 FAIL 状态。
第二个检查是必须的,因为要将一个节点从 PFAIL 状态改变为 FAIL 状态,必须要有大部分主节点进行投票表决,但是,当集群中的大部分主节点都进入失效状态时,单凭一个两个节点是没有办法将一个节点标记为 FAIL 状态的。
因此,有了第二个检查条件,只要集群中的大部分主节点进入了下线状态,那么集群就可以在不请求这些主节点的意见下,将某个节点判断为 FAIL 状态,从而让整个集群停止处理命令请求。
从节点选举
一旦某个主节点进入 FAIL 状态,如果这个主节点有一个或多个从节点存在,那么其中一个从节点会被升级为新的主节点,而其他从节点则会开始对这个新的主节点进行复制。
新的主节点由已下线主节点属下的所有从节点中自行选举产生,以下是选举的条件:
- 这个节点是已下线主节点的从节点。
- 已下线主节点负责处理的槽数量非空。
- 从节点的数据被认为是可靠的, 也即是, 主从节点之间的复制连接(replication link)的断线时长不能超过节点超时时限(node timeout)乘以 REDIS_CLUSTER_SLAVE_VALIDITY_MULT 常量得出的积。
如果一个从节点满足了以上的所有条件,那么这个从节点将向集群中的其他主节点发送授权请求,询问它们,是否允许自己(从节点)升级为新的主节点。
如果发送授权请求的从节点满足以下属性,那么主节点将向从节点返回 FAILOVER_AUTH_GRANTED 授权,同意从节点的升级要求:
- 发送授权请求的是一个从节点, 并且它所属的主节点处于 FAIL 状态。
- 在已下线主节点的所有从节点中, 这个从节点的节点 ID 在排序中是最小的。
- 这个从节点处于正常的运行状态: 它没有被标记为 FAIL 状态, 也没有被标记为 PFAIL 状态。
一旦某个从节点在给定的时限内得到大部分主节点的授权,它就会开始执行以下故障转移操作:
- 通过 PONG 数据包(packet)告知其他节点, 这个节点现在是主节点了。
- 通过 PONG 数据包告知其他节点, 这个节点是一个已升级的从节点(promoted slave)。
- 接管(claiming)所有由已下线主节点负责处理的哈希槽。
- 显式地向所有节点广播一个 PONG 数据包, 加速其他节点识别这个节点的进度, 而不是等待定时的 PING / PONG 数据包。
所有其他节点都会根据新的主节点对配置进行相应的更新,特别地:
- 所有被新的主节点接管的槽会被更新。
- 已下线主节点的所有从节点会察觉到 PROMOTED 标志, 并开始对新的主节点进行复制。
- 如果已下线的主节点重新回到上线状态, 那么它会察觉到 PROMOTED 标志, 并将自身调整为现任主节点的从节点。
在集群的生命周期中,如果一个带有 PROMOTED 标识的主节点因为某些原因转变成了从节点,那么该节点将丢失它所带有的 PROMOTED 标识。