天天看點

MongoDB readConcern 原了解析

mongodb 控制讀政策,還有一個 <code>readpreference</code> 的設定,為了避免混淆,先簡單說明下二者的差別。

<code>primary</code> 隻從 primary 節點讀資料,這個是預設設定

<code>primarypreferred</code> 優先從 primary 讀取,primary 不可服務,從 secondary 讀

<code>secondary</code> 隻從 scondary 節點讀資料

<code>secondarypreferred</code> 優先從 secondary 讀取,沒有 secondary 成員時,從 primary 讀取

<code>nearest</code> 根據網絡距離就近讀取

<code>local</code> 能讀取任意資料,這個是預設設定

<code>majority</code> 隻能讀取到『成功寫入到大多數節點的資料』

<code>readpreference</code> 和 <code>readconcern</code> 可以配合使用。

<code>readconcern</code> 的初衷在于解決『髒讀』的問題,比如使用者從 mongodb 的 primary 上讀取了某一條資料,但這條資料并沒有同步到大多數節點,然後 primary 就故障了,重新恢複後 這個primary 節點會将未同步到大多數節點的資料復原掉,導緻使用者讀到了『髒資料』。

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

需要注意的是,<code>readconcern</code> 能保證讀到的資料『不會發生復原』,但并不能保證讀到的資料是最新的,這個官網上也有說明。

有使用者誤以為,<code>readconcern</code> 指定為 majority 時,用戶端會從大多數的節點讀取資料,然後傳回最新的資料。

實際上并不是這樣,無論何種級别的 <code>readconcern</code>,用戶端都隻會從『某一個确定的節點』(具體是哪個節點由 readpreference 決定)讀取資料,該節點根據自己看到的同步狀态視圖,隻會傳回已經同步到大多數節點的資料。

mongodb 要支援 majority 的 readconcern 級别,必須設定<code>replication.enablemajorityreadconcern</code>參數,加上這個參數後,mongodb 會起一個單獨的snapshot 線程,會周期性的對目前的資料集進行 snapshot,并記錄 snapshot 時最新 oplog的時間戳,得到一個映射表。

最新 oplog 時間戳

snapshot

狀态

t0

snapshot0

committed

t1

snapshot1

uncommitted

t2

snapshot2

t3

snapshot3

隻有確定 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 狀态。

使用 <code>readconcern</code> 需要配置<code>replication.enablemajorityreadconcern</code>選項

隻有支援 readcommited 隔離級别的存儲引擎才能支援 <code>readconcern</code>,比如 wiredtiger 引擎,而 mmapv1引擎則不能支援。