Redis 集群怎么实现高可用
高可用首先要解决集群部分失败的场景:
- 当集群内少量节点出现故障时通过自动故障转移保证集群可以对外提供服务。
故障发现
首先需要通过一种健壮的方式识别出节点是否发生了故障。 Redis 集群内节点通过 ping/pong 消息实现节点通讯, 消息不但可以传播节点槽信息,还可以传播其他状态:主从状态、节点故障等。
故障发现也是通过消息传播机制实现的。
- 主观下线
指某个节点任务另外一个节点不可用,即下线状态,这个状态并不是最终的故障判定。只能代表一个节点的意见,可能存在误判。
- 客观下线
指标记一个节点真正的下线, 集群内多个节点都认为该节点不可用。从而达成共识的结果,如果持有槽的主节点故障,要为该节点进行故障转移。
主观下线
集群中每个节点都会定期向其他节点发送 ping 消息,接收节点回复 pong 消息作为响应。如果 cluster-node-timeout 时间内通讯一致失败,则发送节点会任务接收节点存在故障,会把接收节点标记为主观下线(pfail)状态。
客观下线
当节点判断另外一个节点主观下线后,相应的节点状态会在集群中传播,ping/pong 消息的消息体会携带集群其他节点状态数据,当接收节点发现消息体重含主观下线的节点状态,会在本地故障找到故障节点的 ClusterNode 结构,保存到下线报告链。当半数以上持有槽节点都标记节点是主观下线时,触发客观下线。
尝试客观下线
集群中的节点每次接收其他节点的 pfail 状态,都会尝试触发客观下线,流程如下:
- 首次统计有效的下线报告数量,如果小于集群内持有操的主节点总数的一般则退出。
- 当下线报告大于槽主节点数量一半时,标记对应故障节点为客观下线状态。
- 向集群广播一条 fail 信息,通知所有的节点故障节点标记为客观下线,fail 消息的消息体只包含故障节点的 I
其中广播 Fail 消息是集群内客观下线的最后一步:
- 通知集群内所有节点标记故障节点为客观下线状态并立刻生效
- 通知故障节点的从节点触发故障转移流程。
故障恢复
当故障节点变成客观下线之后,如果下线节点是持有槽的主节点,需要从他的一个从节点中选一个替换,从而保证集群的高可用。
故障恢复过程:
- 资格检查
每个从节点都要检查和主节点断线时间,判断是否有资格替换故障的主节点,如果从节点与主节点断线时间超过 cluster-mode-time*cluster-slave-validity-factor, 则当前节点不具备故障转译资格。cluster-slave-validity-factor 默认为10。
- 准备选举时间
当从节点复合故障转译资格,更新触发故障选举的时间,只有到达时间后才能执行后续流程。
- 发起选举
当从节点定时任务检测到达故障选举时间(failover_auth_time)到达后,发起选举流程如下:
- 更新配置纪元
配置纪元是一个只增不减的整数,每个节点自身维护一个配置纪元(clusterNode.configEpoch)标示当前主节点的版本,所有节点的配置纪元都不相等,从节点会复制主节点的配置纪元。整个机器又维护一个全局的配置纪元(clusterState.currentEpoch).用于记录机器内所有主节点日志纪元的最大版本。
- 选举投票
只有持有槽节点才会处理故障选举信息(FAILOVER_AUTH_REQUEST),因为每个持有槽的节点在一个配置纪元内都有唯一的一张选票。当接到第一个请求投票的从节点时回复 FAILOVER_AUTH_ACK 消息作为投票,之后相同配置纪元内其他及选举信息将忽略。
选举过程
投票过程其实是一个领导者选举过程,如果集群内有N个持有槽的主节点代表有N张选票,由于在每个配置纪元内持有槽的主节点只能投票给一个从节点,因此有一个从节点获得 N/2+1 的选票能够保证找出唯一的从节点。
Redis 集群没有直接使用从节点进行领导者选举。主要因为从节点必须大于等于 3个才能保证凑够 N/2+1 个节点。将导致资源浪费。使用集群内所有持有槽的主节点进行领导者选举,即使只有一个从节点也可以完成选举过程。当从节点收集到 N/2+1 持有槽的主节点投票时,从节点可以执行替换主节点操作。
替换主节点
- 当前从节点强制变成主节点。
- 执行 cluserDelSlot 操作撤销故障主节点负责的槽,并执行 CluserAddSlot 将这些槽委派给自己。
- 向集群广播自己的pong 消息,通知集群内所有节点当前从节点变为主节点并接管了故障主节点的槽信息。