《MongoDB高手課》學習記錄(第十八天)

第十八天

今天要學習的章節是《21 | 事務開發:讀操做事務之二》,繼續昨天的話題,昨天講的是從哪讀readPreference,今天講的是要讀什麼樣的數據readConcern。數據庫

什麼是 readConcern?

在 readPreference 選擇了指定的節點後,readConcern 決定這個節點上的數據哪些是可讀的,相似於關係數據庫的隔離級別。可選值包括:安全

  • available:讀取全部可用的數據;
  • local:讀取全部可用且屬於當前分片的數據,這個是默認值;
  • majority:讀取在大多數節點上提交完成的數據;
  • linearizable:可線性化讀取文檔;
  • snapshot:讀取最近快照中的數據,這個在第三章中講;

readConcern: local 和 available

image.png
在複製集中 local 和 available 是沒有區別的。二者的區別主要體如今分片集上。考慮如下場景:oracle

  • 一個 chunk x 正在從 shard1 向 shard2 遷移;
  • 整個遷移過程當中 chunk x 中的部分數據會在 shard1 和 shard2 中同時存在,但源分片 shard1仍然是chunk x 的負責方:
  • 全部對 chunk x 的讀寫操做仍然進入 shard1;
  • config 中記錄的信息 chunk x 仍然屬於 shard1;
  • 此時若是讀 shard2,則會體現出 local 和 available 的區別:
  • local:只取應該由 shard2 負責的數據(不包括 x);
  • available:shard2 上有什麼就讀什麼(包括 x);

readConcern: local 和 available

注意事項:分佈式

  • 雖然看上去老是應該選擇 local,但畢竟對結果集進行過濾會形成額外消耗。在一些可有可無的場景(例如統計)下,也能夠考慮 available;
  • MongoDB <=3.6 不支持對從節點使用 {readConcern: "local"};
  • 從主節點讀取數據時默認 readConcern 是 local,從從節點讀取數據時默認readConcern 是 available(向前兼容緣由)。

readConcern: majority

說白了,就是超過一半的節點數據提交成功,纔會讀取出
image.png學習

readConcern: majority 的實現方式

image.png
考慮 t3 時刻的 Secondary1,此時:spa

  • 對於要求 majority 的讀操做,它將返回 x=0;
  • 對於不要求 majority 的讀操做,它將返回 x=1;

如何實現?
節點上維護多個 x 版本,MVCC 機制
MongoDB 經過維護多個快照來連接不一樣的版本:code

  • 每一個被大多數節點確認過的版本都將是一個快照;
  • 快照持續到沒有人使用爲止才被刪除;

實驗: readConcern : 」majority」 vs 「local」server

  • 安裝 3 節點複製集。
  • 注意配置文件內 server 參數 enableMajorityReadConcern

image.png

  • 將複製集中的兩個從節點使用 db.fsyncLock() 鎖住寫入(模擬同步延遲)

readConcern 驗證

  • db.test.save({「A」:1})
  • db.test.find().readConcern(「local」)
  • db.test.find().readConcern(「majority」)
  • 在某一個從節點上執行 db.fsyncUnlock()
  • 結論:
  • 使用 local 參數,則能夠直接查詢到寫入數據
  • 使用 majority,只能查詢到已經被多數節點確認過的數據
  • update 與 remove 與上同理

readConcern: majority 與髒讀

這個其實就和oracle的事務一個樣
MongoDB 中的回滾:blog

  • 寫操做到達大多數節點以前都是不安全的,一旦主節點崩潰,而從節還沒複製到該次操做,剛纔的寫操做就丟失了;
  • 把一次寫操做視爲一個事務,從事務的角度,能夠認爲事務被回滾了。

因此從分佈式系統的角度來看,事務的提交被提高到了分佈式集羣的多個節點級別的「提交」,而再也不是單個節點上的「提交」。
在可能發生回滾的前提下考慮髒讀問題:事務

  • 若是在一次寫操做到達大多數節點前讀取了這個寫操做,而後由於系統故障該操做回滾了,則發生了髒讀問題;

使用 {readConcern: 「majority」} 能夠有效避免髒讀

readConcern: 如何實現安全的讀寫分離

image.png
考慮以下場景:

向主節點寫入一條數據;
當即從從節點讀取這條數據。

如何保證本身可以讀到剛剛寫入的數據?

下述方式有可能讀不到剛寫入的訂單

db.orders.insert({ oid: 101, sku: 」kite", q: 1})
db.orders.find({oid:101}).readPref("secondary")

使用 writeConcern + readConcern majority 來解決

db.orders.insert({ oid: 101, sku: "kiteboar", q: 1}, {writeConcern:{w: "majority」}})
db.orders.find({oid:101}).readPref(「secondary」).readConcern("majority")

readConcern: linearizable

只讀取大多數節點確認過的數據。和 majority 最大差異是保證絕對的操做線性順序,在寫操做天然時間後面的發生的讀,必定能夠讀到以前的寫

  • 只對讀取單個文檔時有效;
  • 可能致使很是慢的讀,所以老是建議配合使用 maxTimeMS;

image.png

readConcern: snapshot

{readConcern: 「snapshot」} 只在多文檔事務中生效。將一個事務的 readConcern
設置爲 snapshot,將保證在事務中的讀:

  • 不出現髒讀;
  • 不出現不可重複讀;
  • 不出現幻讀。

由於全部的讀都將使用同一個快照,直到事務提交爲止該快照才被釋放。

readConcern: 小結

  • available:讀取全部可用的數據
  • local:讀取全部可用且屬於當前分片的數據,默認設置
  • majority:數據讀一致性的充分保證,可能你最須要關注的
  • linearizable:加強處理 majority 狀況下主節點失聯時候的例外狀況
  • snapshot:最高隔離級別,接近於 Seriazable
相關文章
相關標籤/搜索