1. 程式人生 > >MongoDB readConcern 原理解析

MongoDB readConcern 原理解析

摘要: MongoDB 可以通過 writeConcern 來定製寫策略,3.2版本後又引入了 readConcern 來靈活的定製讀策略。 readConcern vs readPreference MongoDB 控制讀策略,還有一個 readPreference 的設定,為了避免混淆,先簡單說明下

MongoDB 可以通過 writeConcern 來定製寫策略,3.2版本後又引入了 readConcern 來靈活的定製讀策略。

readConcern vs readPreference

MongoDB 控制讀策略,還有一個 readPreference 的設定,為了避免混淆,先簡單說明下二者的區別。

  • readPreference 主要控制客戶端 Driver 從複製集的哪個節點讀取資料,這個特性可方便的實現讀寫分離、就近讀取等策略。

    • primary 只從 primary 節點讀資料,這個是預設設定
    • primaryPreferred 優先從 primary 讀取,primary 不可服務,從 secondary 讀
    • secondary 只從 scondary 節點讀資料
    • secondaryPreferred 優先從 secondary 讀取,沒有 secondary 成員時,從 primary 讀取
    • nearest 根據網路距離就近讀取
  • readConcern

     決定到某個讀取資料時,能讀到什麼樣的資料。

    • local 能讀取任意資料,這個是預設設定
    • majority 只能讀取到『成功寫入到大多數節點的資料』

readPreference 和 readConcern 可以配合使用。

readConcern 解決什麼問題?

readConcern 的初衷在於解決『髒讀』的問題,比如使用者從 MongoDB 的 primary 上讀取了某一條資料,但這條資料並沒有同步到大多數節點,然後 primary 就故障了,重新恢復後 這個primary 節點會將未同步到大多數節點的資料回滾掉,導致使用者讀到了『髒資料』。

當指定 readConcern 級別為 majority 時,能保證使用者讀到的資料『已經寫入到大多數節點』,而這樣的資料肯定不會發生回滾,避免了髒讀的問題。

需要注意的是,readConcern 能保證讀到的資料『不會發生回滾』,但並不能保證讀到的資料是最新的,這個官網上也有說明。

Regardless of the read concern level, the most recent data on a node may not reflect the most recent version of the data in the system.

有使用者誤以為,readConcern 指定為 majority 時,客戶端會從大多數的節點讀取資料,然後返回最新的資料。

實際上並不是這樣,無論何種級別的 readConcern,客戶端都只會從『某一個確定的節點』(具體是哪個節點由 readPreference 決定)讀取資料,該節點根據自己看到的同步狀態檢視,只會返回已經同步到大多數節點的資料。

readConcern 實現原理

MongoDB 要支援 majority 的 readConcern 級別,必須設定replication.enableMajorityReadConcern引數,加上這個引數後,MongoDB 會起一個單獨的snapshot 執行緒,會週期性的對當前的資料集進行 snapshot,並記錄 snapshot 時最新 oplog的時間戳,得到一個對映表。

最新 oplog 時間戳 snapshot 狀態
t0 snapshot0 committed
t1 snapshot1 uncommitted
t2 snapshot2 uncommitted
t3 snapshot3 uncommitted

只有確保 oplog 已經同步到大多數節點時,對應的 snapshot 才會標記為 commmited,使用者讀取時,從最新的 commited 狀態的 snapshot 讀取資料,就能保證讀到的資料一定已經同步到的大多數節點。

關鍵的問題就是如何確定『oplog 已經同步到大多數節點』?

primary 節點

secondary 節點在 自身oplog發生變化時,會通過 replSetUpdatePosition 命令來將 oplog 進度立即通知給 primary,另外心跳的訊息裡也會包含最新 oplog 的資訊;通過上述方式,primary 節點能很快知道 oplog 同步情況,知道『最新一條已經同步到大多數節點的 oplog』,並更新 snapshot 的狀態。比如當t2已經寫入到大多資料節點時,snapshot1、snapshot2都可以更新為 commited 狀態。(不必要的 snapshot也會定期被清理掉)

secondary 節點

secondary 節點拉取 oplog 時,primary 節點會將『最新一條已經同步到大多數節點的 oplog』的資訊返回給 secondary 節點,secondary 節點通過這個oplog時間戳來更新自身的 snapshot 狀態。

注意事項

  • 目前 readConcern 主要用於跟 mongos 與 config server 的互動上,參考MongoDB Sharded Cluster 路由策略
  • 使用 readConcern 需要配置replication.enableMajorityReadConcern選項
  • 只有支援 readCommited 隔離級別的儲存引擎才能支援 readConcern,比如 wiredtiger 引擎,而 mmapv1引擎則不能支援。

本文為雲棲社群原創內容,未經允許不得轉載,如需轉載請傳送郵件至[email protected];如果您發現本社群中有涉嫌抄襲的內容,歡迎傳送郵件至:[email protected] 進行舉報,並提供相關證據,一經查實,本社群將立刻刪除涉嫌侵權內容。

【雲棲快訊】誠邀您免費學習【阿里雲總監課】!首次集齊12位阿里雲技術高管,從理論到實踐傾囊相授,還有30元代金券,戳鏈