MongoDB oplog詳解

kunlunzhiying發表於2017-12-22

MongoDB oplog詳解

1:oplog簡介

oplog是local庫下的一個固定集合,Secondary就是通過檢視Primary 的oplog這個集合來進行復制的。每個節點都有oplog,記錄這從主節點複製過來的資訊,這樣每個成員都可以作為同步源給其他節點。

 Oplog 可以說是Mongodb Replication的紐帶了。

2:副本集資料同步的過程

副本集中資料同步的詳細過程:Primary節點寫入資料,Secondary通過讀取Primary的oplog得到複製資訊,開始複製資料並且將複製資訊寫入到自己的oplog。如果某個操作失敗(只有當同步源的資料損壞或者資料與主節點不一致時才可能發生),則備份節點停止從當前資料來源複製資料。如果某個備份節點由於某些原因掛掉了,當重新啟動後,就會自動從oplog的最後一個操作開始同步,同步完成後,將資訊寫入自己的oplog,由於複製操作是先複製資料,複製完成後再寫入oplog,有可能相同的操作會同步兩份,不過MongoDB在設計之初就考慮到這個問題,將oplog的同一個操作執行多次,與執行一次的效果是一樣的。

  • 作用:

  當Primary進行寫操作的時候,會將這些寫操作記錄寫入Primary的Oplog 中,而後Secondary會將Oplog 複製到本機並應用這些操作,從而實現Replication的功能。
  同時由於其記錄了Primary上的寫操作,故還能將其用作資料恢復。
  可以簡單的將其視作Mysql中的binlog。

3:oplog的增長速度

oplog是固定大小,他只能儲存特定數量的操作日誌,通常oplog使用空間的增長速度跟系統處理寫請求的速度相當,如果主節點上每分鐘處理1KB的寫入資料,那麼oplog每分鐘大約也寫入1KB資料。如果單次操作影響到了多個文件(比如刪除了多個文件或者更新了多個文件)則oplog可能就會有多條操作日誌。db.testcoll.remove() 刪除了1000000個文件,那麼oplog中就會有1000000條操作日誌。如果存在大批量的操作,oplog有可能很快就會被寫滿了。

  • 大小:

  Oplog 是一個capped collection。
  在64位的Linux, Solaris, FreeBSD, and Windows 系統中,Mongodb預設將其大小設定為可用disk空間的5%(預設最小為1G,最大為50G)或也可以在mongodb複製集例項初始化之前將mongo.conf中oplogSize設定為我們需要的值

  local.oplog.rs 一個capped collection集合.可在命令列下使用--oplogSize 選項設定該集合大小尺寸.
  但是由於Oplog 其保證了複製的正常進行,以及資料的安全性和容災能力。

4:oplog注意事項:

local.oplog.rs特殊的集合。用來記錄Primary節點的操作

為了提高複製的效率,複製集中的所有節點之間會相互的心跳檢測(ping)。每個節點都可以從其他節點上獲取oplog。

oplog中的一條操作。不管執行多少次效果是一樣的

5:oplog的大小

第一次啟動複製集中的節點時,MongoDB會建立Oplog,會有一個預設的大小,這個大小取決於機器的作業系統

rs.printReplicationInfo()     檢視 oplog 的狀態,輸出資訊包括 oplog 日誌大小,操作日誌記錄的起始時間。

db.getReplicationInfo()   可以用來檢視oplog的狀態、大小、儲存的時間範圍。

oplog的大小

capped collection是MongoDB中一種提供高效能插入、讀取和刪除操作的固定大小集合,當集合被填滿的時候,新的插入的文件會覆蓋老的文件。

所以,oplog表使用capped collection是合理的,因為不可能無限制的增長oplog。MongoDB在初始化副本集的時候都會有一個預設的oplog大小:

  • 在64位的Linux,Solaris,FreeBSD以及Windows系統上,MongoDB會分配磁碟剩餘空間的5%作為oplog的大小,如果這部分小於1GB則分配1GB的空間
  • 在64的OS X系統上會分配183MB
  • 在32位的系統上則只分配48MB

oplog的大小設定是值得考慮的一個問題,如果oplog size過大,會浪費儲存空間;如果oplog size過小,老的oplog記錄很快就會被覆蓋,那麼當機的節點就很容易出現無法同步資料的現象。

比如,基於上面的例子,我們停掉一個備份節點(port=33333),然後通過主節點插入以下記錄,然後檢視oplog,發現以前的oplog已經被覆蓋了。

通過MongoDB shell連線上這個節點,會發現這個節點一直處於RECOVERING狀態

解決方法:

資料同步

在副本集中,有兩種資料同步方式:

  • initial sync(初始化):這個過程發生在當副本集中建立一個新的資料庫或其中某個節點剛從當機中恢復,或者向副本集中新增新的成員的時候,預設的,副本集中的節點會從離它最近的節點複製oplog來同步資料,這個最近的節點可以是primary也可以是擁有最新oplog副本的secondary節點。
    • 該操作一般會重新初始化備份節點,開銷較大
  • replication(複製):在初始化後這個操作會一直持續的進行著,以保持各個secondary節點之間的資料同步。

initial sync

當遇到上面例子中無法同步的問題時,只能使用以下兩種方式進行initial sync了

  • 第一種方式就是停止該節點,然後刪除目錄中的檔案,重新啟動該節點。這樣,這個節點就會執行initial sync
    • 注意:通過這種方式,sync的時間是根據資料量大小的,如果資料量過大,sync時間就會很長
    • 同時會有很多網路傳輸,可能會影響其他節點的工作
  • 第二種方式,停止該節點,然後刪除目錄中的檔案,找一個比較新的節點,然後把該節點目錄中的檔案拷貝到要sync的節點目錄中

通過上面兩種方式中的一種,都可以重新恢復"port=33333"的節點。改變一直處於RECOVERING狀態的錯誤。

 

6:oplog資料結構

下面來分析一下oplog中欄位的含義,通過下面的命令取出一條oplog:

db.oplog.rs.find().skip(1).limit(1).toArray()
  • ts: 8位元組的時間戳,由4位元組unix timestamp + 4位元組自增計數表示。這個值很重要,在選舉(如master當機時)新primary時,會選擇ts最大的那個secondary作為新primary
  • op:1位元組的操作型別
    • "i": insert
    • "u": update
    • "d": delete
    • "c": db cmd
    • "db":宣告當前資料庫 (其中ns 被設定成為=>資料庫名稱+ '.')
    • "n": no op,即空操作,其會定期執行以確保時效性
  • ns:操作所在的namespace
  • o:操作所對應的document,即當前操作的內容(比如更新操作時要更新的的欄位和值)
  • o2: 在執行更新操作時的where條件,僅限於update時才有該屬性

檢視oplog的資訊

通過"db.printReplicationInfo()"命令可以檢視oplog的資訊

欄位說明:

  • configured oplog size: oplog檔案大小
  • log length start to end: oplog日誌的啟用時間段
  • oplog first event time: 第一個事務日誌的產生時間
  • oplog last event time: 最後一個事務日誌的產生時間
  • now: 現在的時間

檢視slave狀態

通過"db.printSlaveReplicationInfo()"可以檢視slave的同步狀態

副本節點中執行db.printSlaveReplicationInfo()命令可以檢視同步狀態資訊

  • source——從庫的IP及埠
  • syncedTo——當前的同步情況,延遲了多久等資訊

當我們插入一條新的資料,然後重新檢查slave狀態時,就會發現sync時間更新了

參考文章

作者:Joan
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連線,否則保留追究法律責任的權利。

相關文章