乐趣区

Redis-Cluster配置传播及故障恢复笔记

本笔记是对 Redis Cluster Spec – Configuration handling, propagation, and failovers 的归纳总结。

Epoch

  • 可以把 Epoch 当作是一个版本号,是一个 64 位无符号整形
  • 每个 Node 自己有一份 Cluster.currentEpoch、MySelf.configEpoch、其他 Node.configEpoch,详见文档。
  • 每个 Master 有自己的 ConfigEpoch 且在整个 Cluster 中唯一
  • Slave 的 ConfigEpoch 随其 Master
  • Cluster.currentEpoch,该值等于所有 Node 中最大的 ConfigEpoch 的值
  • Master 的 ConfigEpoch 初始值是 0,也就是说 Cluster.CurrentEpoch 的初始值也是 0
  • Node 之间 Gossip 传输消息时,Receiver 发现 Sender 的 ConfigEpoch 比自己大,那么就更新自己的 Cluster.CurrentEpoch 为该值,随时间收敛,所有 Node 的 Cluster.CurrentEpoch 都变成一样。

Slave Promotion

Slave 的动作

下面是总结的在发生 Slave Promotion 时,Slave 做的事情。

Master 的动作

下面是总结的在发生 Slave Promotion 时,Master 做的事情。

传播 Slots 的配置

Slave 赢得选举之后会在己侧更新 Slots 上的归属信息,然后在定时的 PING/PONG 中将这个信息传播出去。

PING/PONG 总是会携带上 Slots 所属 Master 的信息(包括 ConfigEpoch)

PING 的 Reciever 如果发现 Sender 的某个 Slot 上的 Master.ConfigEpoch 比自己这里记录的小,那么就会返回 UPDATE 告诉 Sender 更新 Slots 归属信息。

下面是两个规则:

  1. 如果一个 Slot 不属于任何 Master,然后有一个 Master 宣称拥有它,那么就修改己侧的 Slots 信息把这个 Slot 关联到这个 Master 上。
  2. 如果一个 Slot 已经归属一个 Master,然后又有一个 Master 宣称拥有它,那么就看谁的 ConfigEpoch 大,大的那个赢

Node 复活后遇到的问题

Node A 有两个 Slot,然后它死了,它被顶替了,等它复活时发现两个 Slot 一个被 Node B 接管,另一个被 Node C 接管了,那么它:

  1. 因为自己的 ConfigEpoch 已经很旧了,所以它复活后不负责任何 Slot
  2. 然后它会成为最后一个 Slot 的 Master 的 Slave

Slave 迁移算法

Slave 迁移时一个自动过程。

举个例子,现在有 Master A、B,它们对应的 Slave 有 A1、B1、B2。现在 A 死了,A1 顶替上去,不过这个时候 A1 就是一个光棍 Master(它没有 Slave),B 有富余的 Slave(B1 和 B2),把其中一个匀给 A1 当 Slave。

这个过程不需要共识,因为只是修改 Slave 的归属,也不会修改 ConfigEpoch。

Slave 迁移有两个规则:

  1. 当有多个 Slave 富余时,选择 NodeID 字典顺最小的那个来迁移
  2. 只有当 Master 的 Slave 数量 >=cluster-migration-barrier时,才会挑选它的 Slave 做 Migration

两个跳过共识修改 ConfigEpoch 的操作

下面两个操作比较危险,最好确定一个成功后再执行另一个:

  • CLUSTER_FAILOVER TAKEOVER(手动 Failover)直接将一个 Slave 提升为 Master,不需要大多数 Master 同意。
  • Slot Migration 同样不需要大多数 Master 同意。

所以就有可能出现同一个 Slot 有两个相同 ConfigEpoch 的 Master 宣称由自己负责,这种冲突的解决算法是:

  • 如果 Master A 发现 Master B 也宣称了对 Slot X 的主权,并且两者的 ConfigEpoch 一样
  • 如果 Master A 的 NodeID 的字典顺比 Master B 的小
  • 那么 Master A 就把己侧的 CurrentEpoch+1,同时 ConfigEpoch 改成和 CurrentEpoch 一样

Node 重制

略,见文档。

移除 Node

略,见文档。

一些自问自答

Q:ConfigEpoch 何时变化?

A:Slave Promotion 时、手动 Failover 时、Slot Migration 时

Q:ConfigEpoch 怎么变化?

A:Node->ConfigEpoch = Cluster->CurrentEpoch + 1,结果也就是 Cluster->CurrentEpoch 加 1 了。源码见这里。

Q:两个 Master 的 ConfigEpoch 一样怎么办?

A:这个会出现在两个 Slave 同时 Promotion 时,解决办法是 NodeID 字典序比较小的那个会再一次 Bump ConfigEpoch,源码见这里。

Q:ConfigEpoch 有什么用?

A:当有两个 Master 宣称自己拥有同一个 / 批 Slot 时,ConfigEpoch 大的那个赢,因为大的那个代表最新信息,其他 Node 只会采用赢的那方所宣称的信息。

Q:CurrentEpoch 有什么用?

A:1)用来判定 Node 所获得的 Cluster 信息的新旧。2)当 Node 要变更 ConfigEpoch 时派用处。

参考资料

官方文档:

  • Redis Cluster Spec – Configuration handling, propagation, and failovers

下面是饿了么工程师写的文章,比较透彻:

  • Redis Cluster 原理与管理

下面是两篇阿里工程师的:

  • 深入理解 redis cluster 的 failover 机制
  • 深入解析 redis cluster gossip 机制
退出移动版