Skip to main content

mongodb-pv1

📅 2026-04-18 ✏️ 2026-04-18 CS
No related notes

1 · MongoDB PV1 (Protocol Version 1)#

  • S: MongoDB 副本集需要动态增删节点 (reconfiguration) 来替换故障节点或扩容
  • C: PV0 依赖时钟同步、无 term、旧 reconfig 协议有安全性 bug (不同 config 的 majority 可能不相交)
  • Q: 如何保留 logless gossip-based 架构优势,同时保证安全性?
  • A: PV1 引入 Raft term;MongoRaftReconfig (MongoDB 4.4) 通过三条规则 + TLA+ 验证实现安全的 logless reconfig

1.1 · PV1 核心机制 (vs PV0)#

特性PV0PV1
选举机制依赖时钟同步 + veto引入 term (任期) 概念
双主检测时钟同步(不可靠)term 比较(快速准确)
Double Voting30s buffer 无法完全防止term 天然防止
w: "majority" 写入可能丢失 ❌保证持久化
readConcern: "majority"不支持支持 ✅
Veto支持(复杂)不支持(简化: 投票即可)
优先级选举保证最高优先级节点当选best-effort

1.1.1 · PV1 的 Raft 适配#

MongoDB PV1 基于 Raft,但有关键差异:

  1. Pull-based 同步 (vs Raft 的 push-based)

    • Raft: primary 主动推送 log entries 给 followers
    • MongoDB: secondary 主动拉取数据,任意两个 replica 间都可发起同步
    • 好处: 支持 chained replication(链式复制),降低 primary 带宽压力和跨地域同步成本
  2. Apply-first, then replicate

    • MongoDB 先将写操作 apply 到存储引擎,再通过 oplog 同步
    • 与 Raft 的”先 commit 再 apply”不同
  3. Dry-run elections (预选举)

    • 正式选举前先发起 dry-run,避免无意义的 term 增长
  4. Oplog 作为 Raft log

    • ts (timestamp) = Raft log index
    • t (term) = Raft term
    • h (hash) = GTID (用于 oplog 完整性校验)

1.1.2 · Oplog Entry 示例#

// PV0: 没有 term
{ "ts": Timestamp(1444466011, 1),
  "h": NumberLong("-6240522391332325619"),
  "op": "i", "ns": "test.col", ... }

// PV1: 增加 term 字段 "t"
{ "ts": Timestamp(1445632081, 861),
  "t": NumberLong(42),     // ← Raft term
  "h": NumberLong("5466055178864103715"),
  "op": "u", "ns": "ycsb.usertable", ... }

1.2 · MongoRaftReconfig: 安全的 Logless 重配置协议#

1.2.1 · 为什么 Raft 原生 reconfiguration 不适用#

Raft 将 config 变更作为特殊的 log entry 写入 oplog,与数据复制紧耦合。MongoDB 旧协议将 config 独立于 oplog,通过心跳 gossip 传播 (logless)——这个设计有性能优势(reconfiguration 可以绕过 oplog 瓶颈),但安全性缺乏保证。

1.2.2 · 核心问题: Quorum 交集#

动态重配置的根本挑战: 不同 config 的 majority 必须相交

例: C1 = {n1, n2, n3}, C2 = {n1, n2, n3, n4, n5}
Q1 = {n1, n2} (C1 的 majority)
Q2 = {n3, n4, n5} (C2 的 majority)
Q1 ∩ Q2 = ∅  ← 危险! 可能出现双主

仅限制 single-node changes 不够:

  • 相邻 config 的 quorum 保证相交
  • 但连续多次变更后,间隔的 config 之间可能不相交

1.2.3 · MongoRaftReconfig 的三条安全规则#

1. Config Quorum Check (配置仲裁检查)

执行 reconfig 前,当前 config 的 majority 节点必须已持有相同 config version

确保旧 config 被 “deactivated”——不能有两个活跃 config 同时运行。

2. Term Quorum Check (任期仲裁检查)

primary 的 config 中,majority 节点的 term ≥ primary 当前 term

确保 term 信息在 config 间正确传播,防止旧 term 的 primary 在新 config 中仍有效。

3. Oplog Commitment Rule (Oplog 提交规则)

reconfig 前,当前 term 的 至少一条 oplog entry 必须已在 majority 上提交

确保旧 config 中已 commit 的数据被转移到新 config 中。Raft 将 config 放在 log 里隐式保证了这一点,logless 设计需要显式检查。

1.2.4 · 概念模型: Config 作为 Logless 状态机#

MongoRaftReconfig 的核心洞察:

Config 本身可以看作一个独立的、无日志的复制状态机 (Logless RSM)

  • 不需要维护 config 历史,只需最新 config 生效
  • 心跳传播 config ≈ Raft 的 “append to log”
  • 永远安装更新的 config,无需显式回滚
  • 与 oplog RSM 独立运行,但通过上述三条规则保证交互安全

1.2.5 · 两个核心方面

方面含义对应规则
Config Deactivation旧 config 不能与新 config 同时活跃Config Quorum Check + Term Quorum Check
State Transfer旧 config 的已提交状态必须传递到新 configOplog Commitment Rule

1.3 · 参考资料