没复制出去的写入去哪了?这篇在 3 节点副本集上让旧 primary 带着 5 个未复制的 w:1 写入崩溃,看新 primary 的选出、旧 primary 重启后的回滚过程、日志、rollback 目录里的 BSON 文件和最终的数据。
节点 9901:15 个文档,_id>=100 的有 5 个 节点 9902:10 个文档,_id>=100 的有 0 个 节点 9903:10 个文档,_id>=100 的有 0 个
让两个 secondary 停止拉取 oplog,在 primary 上用 w:1 写入 5 个文档(没有任何副本有),再把 primary 杀掉。
10.6 s 后选出新 primary 9902(原来的 primary 是 9901) 新 primary 上写入 3 个文档(_id 200~202,w:majority)后,文档数 13,_id>=100 的 [200, 201, 202]
两个 secondary 在约 10 秒后选出新 primary,继续接受写入,但它没有那 5 个文档。
旧 primary 的状态(距重启秒数): [(0.62, 'SECONDARY')]
旧 primary 重启后 oplog 获取器发现与同步源分叉,进入 ROLLBACK,使用 recoverToStableTimestamp 方式,约 0.5 秒后恢复为 SECONDARY。
状态转换(日志时间 → 新状态):11:52:38.213 STARTUP→STARTUP2;11:52:38.213 STARTUP2→RECOVERING;11:52:38.220 RECOVERING→SECONDARY;11:52:39.241 SECONDARY→ROLLBACK;11:52:39.725 ROLLBACK→SECONDARY 11:52:38.030 Searching for local Rollback ID document 11:52:38.031 Initializing rollback ID 11:52:38.031 Incrementing the rollback ID after unclean shutdown 11:52:38.034 Incremented the rollback ID 11:52:38.035 Initial consistent data is now available 11:52:39.240 Oplog fetcher returned error 11:52:39.240 Starting rollback due to fetcher error 11:52:39.240 Rollback using 'recoverToStableTimestamp' method 11:52:39.240 Scheduling rollback 11:52:39.240 Transition to ROLLBACK 11:52:39.241 Replica set state transition 11:52:39.241 Failed to refresh key cache
被撤销的文档保存在 dbpath/rollback/<集合 UUID>/removed.<时间>.bson 里,可以人工检查后再写回。
rollback 目录里的文件: ['rollback/9a3c21f6-f604-4c6a-a3ef-c4373d4a0f4f/removed.2026-10-12T03-52-39.1.bson', 'rollback/local.oplog.rs/removed.2026-10-12T03-52-39.0.bson']
removed.2026-10-12T03-52-39.1.bson 里的文档: [{'_id': 101, 'src': 'old-primary-only'}, {'_id': 103, 'src': 'old-primary-only'}, {'_id': 104, 'src': 'old-primary-only'}, {'_id': 102, 'src': 'old-primary-only'}, {'_id': 100, 'src': 'old-primary-only'}]回滚后三个节点都是 13 个文档,w:1 的 5 个文档不在集合里。
节点 9901:13 个文档,_id>=100 的 [200, 201, 202] 节点 9902:13 个文档,_id>=100 的 [200, 201, 202] 节点 9903:13 个文档,_id>=100 的 [200, 201, 202]
重要的写入使用 w: majority,已被多数确认的写入不会被回滚。