mongodb-pv1
Outlinks (0)
No outlinks found
Backlinks (0)
No backlinks found
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)#
| 特性 | PV0 | PV1 |
|---|---|---|
| 选举机制 | 依赖时钟同步 + veto | 引入 term (任期) 概念 |
| 双主检测 | 时钟同步(不可靠) | term 比较(快速准确) |
| Double Voting | 30s buffer 无法完全防止 | term 天然防止 |
w: "majority" 写入 | 可能丢失 ❌ | 保证持久化 ✅ |
readConcern: "majority" | 不支持 | 支持 ✅ |
| Veto | 支持(复杂) | 不支持(简化: 投票即可) |
| 优先级选举 | 保证最高优先级节点当选 | best-effort |
1.1.1 · PV1 的 Raft 适配#
MongoDB PV1 基于 Raft,但有关键差异:
-
Pull-based 同步 (vs Raft 的 push-based)
- Raft: primary 主动推送 log entries 给 followers
- MongoDB: secondary 主动拉取数据,任意两个 replica 间都可发起同步
- 好处: 支持 chained replication(链式复制),降低 primary 带宽压力和跨地域同步成本
-
Apply-first, then replicate
- MongoDB 先将写操作 apply 到存储引擎,再通过 oplog 同步
- 与 Raft 的”先 commit 再 apply”不同
-
Dry-run elections (预选举)
- 正式选举前先发起 dry-run,避免无意义的 term 增长
-
Oplog 作为 Raft log
ts(timestamp) = Raft log indext(term) = Raft termh(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 的已提交状态必须传递到新 config | Oplog Commitment Rule |
1.3 · 参考资料
- Rapid Prototyping a Safe, Logless Reconfiguration Protocol for MongoDB with TLA+ (2025 Blog)
- Design and Analysis of a Logless Dynamic Reconfiguration Protocol (OPODIS 2021)
- Fault-Tolerant Replication with Pull-Based Consensus in MongoDB (NSDI 2021)
- MongoRaftReconfig TLA+ Specs
- MongoDB Replica Set Protocol Versions
- MongoDB and Raft (Henrik Ingo, PGDay 2017)