Mongodb的oplog詳解

這篇文章主要介紹了Mongodb的oplog詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨着小編來一起學習學習吧

Oplog 是 MongoDB 實現複製集的關鍵數據結構,在複製集中 Primary 對數據庫操作之後就會產生一個 Oplog 文檔保存在 local.oplog.rs 集合中,Secondary 成員會拉取 Primary 的 Oplog 並重放相同的操作,從而達到 Secondary 成員與 Primary 有一致的數據。實際上覆制集中每一個成員都會保存 Oplog,其他成員會根據連接延遲等因數選擇最近的成員拉取 Oplog 數據。

Oplog 存在集合 local.oplog.rs,這是系統內置集合,一個 capped collection,即是這個 collection 有固定大小,一旦寫滿數據會從頭開始寫入,就像一個圓形的隊列結構。這個 collection 大小在初始化集羣時設置,默認的大小是 5% 的空閒磁盤空間,也可以在配置文件設置 oplogSizeMB 選項,或者在啓動 MongoDB 後使用 replSetResizeOplog 命令動態設置 collection 大小。

Oplog 與 MongoDB 的其他的文檔沒有什麼不同,它固定有一些屬性:

  1. ts: MongoDB 的內置的特殊時間戳數據結構,如 Timestamp(1503110518, 1), 由秒級的 Unix 時間戳和一個順序增長的整數 increment 表示。長度爲 64 位,其中 Unix 時間戳佔 32 位,後 32 位可以保存同一秒內的第幾次操作。
  2. h: hash 值代表每個 Oplog 的唯一標識。
  3. v: Oplog 版本
  4. ns: namespace 命名空間,數據庫+集合,用 database.collection 表示。但如果是表操作命令等,變成 database.$cmd。
  5. op:operation type,操作類型,包含以下幾種:
    1. i: insert, 插入文檔
    2. u: update, 更新文檔
    3. d: delete, 刪除文檔
    4. c: command, 操作命令,如 createIndex 等
    5. n: 空操作,用於空閒時主從同步 Oplog 時間信息
  6. o: operation, Oplog 操作的具體內容,例如 i operation type,o 即是插入的文檔。對於 u operation type, 只更新部分內容, o 鍵的內容爲 {$set: {...}}
  7. o2: 用於 update 操作,包含 _id 屬性值。

Oplog 的重放是冪等(idempotent)的,即是說同一個 Oplog 重放多次最終結果還是一致的。這是 MongoDB 將許多命令操作進行了轉化,保持生成的 Oplog 是可以冪等的,如執行以下 $inc 操作:

db.test.update({_id: ObjectId("533022d70d7e2c31d4490d22")}, {$inc: {count: 1}})

產生的 Oplog 爲:

{
 "ts" : Timestamp(1503110518, 1),
 "t" : NumberLong(8),
 "h" : NumberLong(-3967772133090765679),
 "v" : NumberInt(2),
 "op" : "u",
 "ns" : "mongo.test",
 "o2" : {
  "_id" : ObjectId("533022d70d7e2c31d4490d22")
 },
 "o" : {
  "$set" : {
   "count" : 2.0
  }
 }
}

以上 MongoDB 可以保證 Oplog 的數據操作(DML 語句)是冪等的,但數據表操作(DDL 語句)命令無法保證,例如重複執行相同的 createIndex 命令。

Oplog 的查詢

Capped collection 內文檔是以插入順序排序的,沒有其他索引,但是 local.oplog.rs 是一個特殊的 capped collection,在 Wiredtiger 引擎的話,Oplog 的時間戳會作爲一個特殊的元信息存儲,使得 Oplog 可以以 ts 字段排序,查詢 Oplog 時可以利用 ts 字段篩選。

一般來說 Secondary 同步需要經過 initial sync 和 incremental sync,initial sync 同步完成後,需拉取從同步時間點開始之後的 Oplog 進行持續重放。所以查詢 Oplog 的操作一般是:

db.oplog.rs.find({$gte:{'ts': Timestamp(1503110518, 1)}})

Secondary 需要不斷獲取 Primary 產生的 Oplog, 複製集會使用 tailable cursor 持續獲取 Oplog 數據,非常類似 Unix 系統的 tail -f。這會提高效率,因爲一般的 cursor 使用完畢後就會關閉,而 tailable cursor 會保存上次的 id, 並持續獲取數據。

如果使用 pymongo 驅動器,則定位從某個時間點之後的 Oplog 可以這麼寫:

coll = db['local'].get_collection(
 'oplog.rs',
 codec_options=bson.codec_options.CodecOptions(document_class=bson.son.SON))

cursor = coll.find({'ts': {'$gte': start_optime}},
 cursor_type=pymongo.cursor.CursorType.TAILABLE,
 oplog_replay=True,
 no_cursor_timeout=True)

while True:
 try:
  oplog = cursor.next()
  process(oplog)
 except StopException:
  # 沒有更多的 Oplog 數據
  time.sleep(1)

cursor_type 使用 TAILABLE 或者 TAILABLE_AWAIT,使用後一種類型時,如果沒有更多的 Oplog 數據,則這次請求會阻塞等待有 Oplog 數據或者到達等待的時間超時返回。

設置 oplog_replay 標記可以表示此次請求的類型是保存 Oplog 的 capped collection, 提供 ts 篩選參數, 進行查詢優化。

獲取到 Oplog 之後,就可以做數據同步或者分發到感興趣的消費者作特殊分析,如 MongoShake 工具。

參考了文檔:

Replica Set Oplog: https://docs.mongodb.com/manual/core/replica-set-oplog/
MongoDB oplog 漫談: http://caosiyang.github.io/2016/12/24/mongodb-oplog/
MongoDB複製集原理: https://www.jb51.net/article/166148.htm

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持神馬文庫。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章