欢迎光临
我们一直在努力

跨机房自动 Failover 演练:当核心机房突然掉电时如何做到 RPO=0

跨机房自动 Failover 演练:当核心机房突然掉电时如何做到 RPO=0

封面信息图

在分布式存储的高可用设计中,“同城多机房容灾”是抵御物理世界不可抗风险(如机房变电站起火、市政施工挖断光缆、空调制冷大面积瘫痪)的终极盾牌。

在平时的技术宣讲中,每套架构方案都宣称自己具备“RPO=0(零数据丢失)、RTO<30s(秒级自愈)”的极致容灾能力。

然而,大促前的实战攻坚从来不相信口头承诺。上周四凌晨两点,我们在生产真实的预发与影子多活集群上,进行了一场残酷的全链路突发机房掉电断网实战演练:直接通过机房 PDU 智能电源管理模块,对承载着主库 Leader 的核心机房进行物理强制拉闸!

在真实物理断电的火线中,系统是如何在短短 12 秒内自动完成多数派重新选主、VIP 路由漂移并做到数据零丢失的?

[同城三机房 (2-2-1) 物理拓扑与断电故障转移时序]

┌────────────────────────┐ ┌────────────────────────┐ ┌────────────────────────┐
│ 机房 A (主机房 – 突发掉电!)│ │ 机房 B (同城从机房) │ │ 机房 C (第三见证区) │
│ – Node 1 (原 Leader 挂死)│ │ – Node 3 (Follower) │ │ – Node 5 (Witness 见证)│
│ – Node 2 (Follower 挂死) │ │ – Node 4 (Follower) │ │ (仅参与投票无存储) │
└────────────────────────┘ └───────────┬────────────┘ └───────────┬────────────┘
│ │
└─────────────┬─────────────┘
│ 汇聚 3 票 (3/5 满足多数派!)

[Node 3 成功晋升为新 Leader!]
[VIP 漂移至机房 B, RTO = 12s, RPO = 0]

核心底座一:同城 2-2-1 物理拓扑与法定多数派(Quorum)

要做到机房级掉电时 RPO=0,集群的副本数量与机房分布必须经过严格的数学论证:

我们采用的是经典的 同城三机房 5 副本(2-2-1)架构:

  • 机房 A(主机房):部署 2 个全功能存储副本(包含原 Leader);
  • 机房 B(同城灾备机房):部署 2 个全功能存储副本;
  • 机房 C(第三可用区):部署 1 个不存储全量物理数据的见证节点(Witness / Arbiter),专门用于网络仲裁投票。

数学保证:当机房 A 发生整机房断电、2 个副本瞬间物理死亡时,机房 B(2 票)与机房 C(1 票)能够迅速汇聚 3 票,在总数 5 个副本中达成法定多数派($3 \\ge \\lfloor 5/2 \\rfloor + 1$)。集群无需任何人工介入,天然具备合法选举新 Leader 的数学基础。

12 秒极限自愈的三道时序关卡

在拉闸断电的瞬间,系统经历了一场微秒级的自愈接力赛:

1. 租约过期与断连探测(耗时 3.0 秒)

Node 3 和 Node 4 在机房 A 掉电后,连续 3 次未收到来自原 Leader 的 Raft 心跳(HeartbeatTimeout = 1000ms)。租约计时器触发超时,Node 3 立即将本地状态切换为 Candidate,并在集群中广播 RequestVote。

2. Pre-Vote 预投票与多数派确认(耗时 1.5 秒)

为了防止网络局部抖动引发无意义的 Term 膨胀,Node 3 先发起 Pre-Vote。机房 B 的 Node 4 和机房 C 的见证节点在确认本地未收到 Leader 心跳后,向 Node 3 投出赞成票。Node 3 收集到 3 票后,正式晋升为新 Term 的 Leader,并向存活节点广播第一条空的 Commit 日志,成功将主写入权锁定在机房 B。

3. 路由平滑收敛与 VIP 漂移(耗时 7.5 秒)
  • 全局高可用调度器(Keepalived / BGP Anycast)感知到底层 Leader 切换,自动向机房 B 的接入网关下发 ARP 免费通告,将数据库对外虚 IP(VIP)秒级漂移至机房 B;
  • 应用端微服务连接池(如 HikariCP)检测到原 TCP 连接中断,触发自动重连机制,新连接在 1~2 秒内透明接入机房 B 的新主库。

// 见证节点轻量级投票仲裁核心逻辑
func (w *WitnessNode) HandleRequestVote(req *VoteRequest) *VoteResponse {
w.mu.Lock()
defer w.mu.Unlock()

// 见证节点不检查数据落盘进度,仅依据 Term 和最后日志索引进行合法性仲裁
if req.Term > w.currentTerm && req.LastLogIndex >= w.lastLogIndex {
w.currentTerm = req.Term
w.votedFor = req.CandidateID
return &VoteResponse{Term: w.currentTerm, VoteGranted: true}
}
return &VoteResponse{Term: w.currentTerm, VoteGranted: false}
}

为什么能保证 RPO = 0?

根据多数派提交铁律:任何一笔在机房 A 掉电前已经向业务客户端返回“写入成功”的事务,必然已经成功同步并持久化到了至少 3 个节点上!

这意味着,机房 B 的 Node 3 或 Node 4 中,必然至少有 1 个节点拥有这笔事务的完整 WAL 日志。在 Raft 选举规则中,只有拥有最新、最完整日志的节点才有资格成为新 Leader。因此,新选举出的 Leader 100% 包含了断电前提交的全部数据,从物理数学上锁死了 RPO = 0。

通过定期的断电突袭演练,把故障转移从 PPT 上的理论推演,打造成可以在任何深夜自动生效的确定性工程闭环,这是保障大促稳定性的最高标准。

赞(0)
未经允许不得转载:171主机测评 » 跨机房自动 Failover 演练:当核心机房突然掉电时如何做到 RPO=0
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址