MongoDBNotes

第 15 章:选举与 Raft

zjc 于 2026-01-15 发布

这是《MongoDB 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 MongoDB 副本集选举决定哪个成员成为 Primary。它借鉴并实现了类似 Raft 的共识思想:多数派投票、任期隔离旧主、日志进度参与选主。理解选举,才能理解故障切换时间和脑裂防护。

15.1 为什么需要选举

Primary 故障后必须满足:

  1. 快速选出新 Primary;
  2. 只有大多数成员同意;
  3. 拥有足够新的数据;
  4. 隔离旧 Primary;
  5. 恢复后重新加入。

多数派是防脑裂的核心:

3 members: 2 votes needed
5 members: 3 votes needed

15.2 术语

术语 说明
term 选举任期,任期越高优先级越高
majority 多数投票成员
voting member 有投票权的成员
priority 成为主 的优先级
election timeout 触发选举的等待时间
catch-up 新主追日志,减少回退

MongoDB 实现细节与 Raft 论文并不完全相同,但目标一致。

15.3 选举流程

primary heartbeat lost
  -> secondary becomes candidate
  -> request votes
  -> majority granted
  -> candidate becomes primary
  -> clients update topology

节点会考虑:

  1. 自身健康;
  2. oplog 进度;
  3. priority;
  4. 其他成员状态;
  5. 是否能达到多数;
  6. 心跳连通性。

15.4 任期与旧主隔离

old primary term 10
new primary term 11

旧 Primary 恢复后:

  1. 发现更高任期;
  2. 降级为 Secondary;
  3. 回滚未提交到多数的写入;
  4. 重新同步加入。

这些未提交写入会形成回滚文件,需要人工检查和治理。

15.5 选举触发条件

常见触发:

  1. Primary 进程退出;
  2. Primary 网络隔离;
  3. Primary 延迟过高;
  4. 手动 stepDown;
  5. 副本集重配置;
  6. 维护操作。

主动切换:

rs.stepDown(120)

该命令让当前 Primary 在指定时间内不尝试重新当选。

15.6 选举时间

故障检测和选主需要时间,恢复窗口通常由以下因素决定:

  1. heartbeat 间隔;
  2. election timeout;
  3. 副本同步进度;
  4. 网络延迟;
  5. 节点负载;
  6. 多数成员健康;
  7. DNS 或代理层恢复。

不要假设切换毫秒级完成,应用需要处理连接错误和写超时。

15.7 投票成员设计

推荐:

拓扑 建议
3 节点 三数据节点,跨故障域
5 节点 可容忍两节点故障
跨机房 每个机房故障不破坏多数
云上 跨可用区,不跨账号管理复杂域

避免:

  1. 双节点副本集;
  2. 多数成员在同一宿主机;
  3. Arbiter 长期替代数据副本;
  4. 延迟节点参与关键读路径;
  5. 跨高延迟机房强求同步多数。

15.8 回滚文件

旧 Primary 上未同步到多数的写入可能回滚:

old primary write A -> not replicated
new primary commits B
old primary rejoin -> rollback A

处理:

  1. 查看 rollback 目录;
  2. 判断业务是否需要恢复;
  3. 通过审计或业务侧补偿;
  4. 不要盲目批量回灌;
  5. 保留复盘记录。

使用 majority 写关注可降低应用确认这类写入成功的概率。

15.9 客户端行为

切换期间可能发生:

  1. 连接断开;
  2. NotPrimaryNoSecondaryOK
  3. 写超时;
  4. 重试后成功;
  5. 拓扑刷新延迟。

应用建议:

  1. 使用副本集连接串;
  2. 设置服务发现超时;
  3. 幂等重试;
  4. 有限退避;
  5. 记录请求 ID;
  6. 对切换窗口告警。

15.10 监控与演练

指标:

replica_set_members
member_state
elections_total
election_duration_ms
replication_lag_seconds
rollback_events_total
heartbeat_failure_total

演练:

  1. kill Primary;
  2. 断开 Primary 网络;
  3. 手动 stepDown;
  4. 恢复旧主;
  5. 同时关闭 Secondary;
  6. 跨可用区网络抖动。

验证业务恢复时间、数据一致性和客户端重试成功率。

本章小结

MongoDB 用多数派投票和任期机制选择 Primary,防止分区中出现双主。选举代价是短暂不可写,以及旧主未同步多数的写入可能回滚。生产上应合理设计投票拓扑、使用 majority 写关注并常态化演练切换。

思考题

  1. 为什么多数派能防止脑裂?
  2. term 如何隔离旧 Primary?
  3. 什么写入可能进入回滚文件?
  4. Arbiter 为什么不能替代数据副本?
  5. 故障切换期间应用应如何处理超时?