第十八天
今天要學習的章節是《21 | 事務開發:讀操做事務之二》,繼續昨天的話題,昨天講的是從哪讀readPreference,今天講的是要讀什麼樣的數據readConcern。數據庫
什麼是 readConcern?
在 readPreference 選擇了指定的節點後,readConcern 決定這個節點上的數據哪些是可讀的,相似於關係數據庫的隔離級別。可選值包括:安全
- available:讀取全部可用的數據;
- local:讀取全部可用且屬於當前分片的數據,這個是默認值;
- majority:讀取在大多數節點上提交完成的數據;
- linearizable:可線性化讀取文檔;
- snapshot:讀取最近快照中的數據,這個在第三章中講;
readConcern: local 和 available
![image.png image.png](http://static.javashuo.com/static/loading.gif)
在複製集中 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
說白了,就是超過一半的節點數據提交成功,纔會讀取出
學習
readConcern: majority 的實現方式
![image.png image.png](http://static.javashuo.com/static/loading.gif)
考慮 t3 時刻的 Secondary1,此時:spa
- 對於要求 majority 的讀操做,它將返回 x=0;
- 對於不要求 majority 的讀操做,它將返回 x=1;
如何實現?
節點上維護多個 x 版本,MVCC 機制
MongoDB 經過維護多個快照來連接不一樣的版本:code
- 每一個被大多數節點確認過的版本都將是一個快照;
- 快照持續到沒有人使用爲止才被刪除;
實驗: readConcern : 」majority」 vs 「local」server
- 安裝 3 節點複製集。
- 注意配置文件內 server 參數 enableMajorityReadConcern
![image.png image.png](http://static.javashuo.com/static/loading.gif)
- 將複製集中的兩個從節點使用 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 image.png](http://static.javashuo.com/static/loading.gif)
考慮以下場景:
向主節點寫入一條數據;
當即從從節點讀取這條數據。
如何保證本身可以讀到剛剛寫入的數據?
下述方式有可能讀不到剛寫入的訂單
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 image.png](http://static.javashuo.com/static/loading.gif)
readConcern: snapshot
{readConcern: 「snapshot」} 只在多文檔事務中生效。將一個事務的 readConcern
設置爲 snapshot,將保證在事務中的讀:
由於全部的讀都將使用同一個快照,直到事務提交爲止該快照才被釋放。
readConcern: 小結
- available:讀取全部可用的數據
- local:讀取全部可用且屬於當前分片的數據,默認設置
- majority:數據讀一致性的充分保證,可能你最須要關注的
- linearizable:加強處理 majority 狀況下主節點失聯時候的例外狀況
- snapshot:最高隔離級別,接近於 Seriazable