MongoDB 的複寫機制是其高可用性架構的基石。雖然現代版本(3.0+)已全面推廣 Replica Set(複寫集),但早期的 Master-Slave(主從)模式在架構上更為簡單,適合作為理解複寫核心邏輯的切入點。本文基於 MongoDB 1.6 時代的源碼,深入分析 Master 節點接收寫入操作、生成 oplog、同步至 Slave 的完整流程,並對關鍵資料結構與源碼路徑進行註解。
| 模式 | 特點 | 適用場景 |
|---|---|---|
| Master-Slave | 單向同步、手動故障轉移、Slave 可掛多 Master(不推薦) | 讀寫分離、簡單備份 |
| Replica Pairs | 雙節點自動協商主從、需 Arbiter 仲裁、支援自動故障轉移 | 雙機高可用 |
| Replica Sets(現代標準) | 多節點、自動選舉、自動故障轉移、支援仲裁節點 | 生產環境標準部署 |
# Master 節點
mongod --dbpath=d:/mongodb/db --master --oplogSize 64
# Slave 節點
mongod --dbpath=d:/mongodb/db --slave --source 10.0.1.103:27017 --only test --slavedelay 100
關鍵參數說明:
--oplogSize:指定 oplog 佔用空間(32 位最小 50MB,64 位最小 1GB,上限磁碟 5%)--source:指定 Master 位址(Slave 專用)--only:只同步指定資料庫--slavedelay:同步延遲(秒),防誤刪資料Oplog 存放於 local.oplog.$main 集合,每份文檔代表一個寫入操作,包含四大欄位:
| 欄位 | 類型 | 說明 |
|---|---|---|
ts | Timestamp | 操作時間戳(4 字節秒數 + 4 字節遞增計數器) |
op | char (1 byte) | 操作類型:'i'=insert, 'u'=update, 'd'=delete, 'n'=noop |
ns | string | 命名空間(資料庫.集合名) |
o | BSON object | 操作內容(insert 為文檔本身,update 為修改器,delete 為 _id) |
注意: 唯有改變資料庫狀態的操作會記錄 oplog,查詢操作不記錄。
instance.cpp 中的 assembleResponse// instance.cpp
// Returns false when request includes end
void assembleResponse( Message &m, DbResponse &dbresponse, const SockAddr &client ) {
...
if ( op == dbQuery ) {
if ( handlePossibleShardedMessage( m , &dbresponse ) )
return;
receivedQuery(c , dbresponse, m );
}
// 服務端收到 message 執行相關查詢操作
else if ( op == dbGetMore ) {
if ( ! receivedGetMore(dbresponse, m, currentOp ) )
log = true;
}
...
}
這是網路層接收封包後的分發入口。實際寫入操作(insert/update/delete)會走 dbInsert/dbUpdate/dbDelete 分支,最終進入存儲引擎並觸發 oplog 記錄。
assembleResponse → receivedInsert/receivedUpdate/receivedDeletets, op, ns, o 的 BSON 物件local.oplog.$main:作為 capped collection,自動淘汰舊記錄ts 順序重放操作| 文件 | 核心職責 |
|---|---|
db/repl.rs | 複寫核心邏輯、同步協調、oplog 應用 |
db/instance.cpp | 網路請求分發、命令處理入口 |
db/ops/write_ops.cpp | 寫入操作實作、oplog 生成觸發點 |
db/namespace.cpp | 集合操作、capped collection 管理 |
db/repl/slave.cpp | Slave 同步邏輯、oplog 拉取與重放 |
r1.6 標籤)mongod.sln--master --oplogSize 64instance.cpp::assembleResponse、write_ops.cpp 寫入路徑雖然 Master-Slave 已被淘汰,但其核心設計思想延續至今:
透過閱讀早期 MongoDB 複寫源碼,我們能清晰看到分散式資料庫最核心的問題——「如何在不可靠的網路上維護多副本一致性」——是如何一步步從簡單的主從同步演進為今天成熟的 Replica Set 架構。建議有興趣的讀者進一步研讀 repl.rs 中的同步協調邏輯、slave.cpp 的重放機制,以及現代版本中的 Raft 選舉實作(repl/raft_consensus.cpp)。