MongoDB writeConcern和readConcern原理
目錄
readConcern
readConcern作用
MongoDB 可以利用readConcern
來靈活的定製讀策略,決定讀取資料時,能讀到什麼樣的資料。包含2個選項:
local
能讀取任意資料,這個是預設設定majority
只能讀取到『成功寫入到大多數節點的資料』
readConcern
的初衷在於解決『髒讀』的問題,比如使用者從 MongoDB 的 primary 上讀取了某一條資料,但這條資料並沒有同步到大多數節點,然後 primary 就故障了,重新恢復後 這個primary 節點會將未同步到大多數節點的資料回滾掉,導致使用者讀到了『髒資料』。
當指定 readConcern 級別為 majority 時,能保證使用者讀到的資料『已經寫入到大多數節點』,而這樣的資料肯定不會發生回滾,避免了髒讀的問題。
需要注意的是,readConcern
能保證讀到的資料『不會發生回滾』,但並不能保證讀到的資料是最新的,
有使用者誤以為,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須知
- 目前
readConcern
主要用於跟 mongos 與 config server 的互動上 - 使用
readConcern
需要配置replication.enableMajorityReadConcern
選項 - 只有支援 readCommited 隔離級別的儲存引擎才能支援
readConcern
,比如 wiredtiger 引擎,而 mmapv1引擎則不能支援。
readPreference
MongoDB 控制讀策略,還有一個 readPreference
的設定,主要控制客戶端 Driver 從複製集的哪個節點讀取資料,這個特性可方便的實現讀寫分離、就近讀取等策略。
primary
只從 primary 節點讀資料,這個是預設設定primaryPreferred
優先從 primary 讀取,primary 不可服務,從 secondary 讀secondary
只從 scondary 節點讀資料secondaryPreferred
優先從 secondary 讀取,沒有 secondary 成員時,從 primary 讀取nearest
根據網路距離就近讀取
writeConcern
MongoDB支援客戶端靈活配置寫入策略(writeConcern),以滿足不同場景的需求。
db.collection.insert({x: 1}, {writeConcern: {w: 1}})
writeConcern選項
MongoDB支援的WriteConncern選項如下
-
w: <number>,資料寫入到number個節點才向用客戶端確認
- {w: 0} 對客戶端的寫入不需要傳送任何確認,適用於效能要求高,但不關注正確性的場景
- {w: 1} 預設的writeConcern,資料寫入到Primary就向客戶端傳送確認
- {w: "majority"} 資料寫入到副本集大多數成員後向客戶端傳送確認,適用於對資料安全性要求比較高的場景,該選項會降低寫入效能
-
j: <boolean> ,寫入操作的journal持久化後才向客戶端確認
- 預設為"{j: false},如果要求Primary寫入持久化了才向客戶端確認,則指定該選項為true
-
wtimeout: <millseconds>,寫入超時時間,僅w的值大於1時有效。
- 當指定{w: }時,資料需要成功寫入number個節點才算成功,如果寫入過程中有節點故障,可能導致這個條件一直不能滿足,從而一直不能向客戶端傳送確認結果,針對這種情況,客戶端可設定wtimeout選項來指定超時時間,當寫入過程持續超過該時間仍未結束,則認為寫入失敗。
{w: "majority"}解析
{w: 1}、{j: true}等writeConcern選項很好理解,Primary等待條件滿足傳送確認;但{w: "majority"}則相對複雜些,需要確認資料成功寫入到大多數節點才算成功,而MongoDB的複製是通過Secondary不斷拉取oplog並重放來實現的,並不是Primary主動將寫入同步給Secondary,那麼Primary是如何確認資料已成功寫入到大多數節點的?
- Client向Primary發起請求,指定writeConcern為{w: "majority"},Primary收到請求,本地寫入並記錄寫請求到oplog,然後等待大多數節點都同步了這條/批oplog(Secondary應用完oplog會向主報告最新進度)。
- Secondary拉取到Primary上新寫入的oplog,本地重放並記錄oplog。為了讓Secondary能在第一時間內拉取到主上的oplog,find命令支援一個awaitData的選項,當find沒有任何符合條件的文件時,並不立即返回,而是等待最多maxTimeMS(預設為2s)時間看是否有新的符合條件的資料,如果有就返回;所以當新寫入oplog時,備立馬能獲取到新的oplog。
- Secondary上有單獨的執行緒,當oplog的最新時間戳發生更新時,就會向Primary傳送replSetUpdatePosition命令更新自己的oplog時間戳。
- 當Primary發現有足夠多的節點oplog時間戳已經滿足條件了,向客戶端傳送確認。
參考:阿里雲MongoDB
相關文章
- MongoDB學習4:MongoDB複製集機制和原理,搭建複製集MongoDB
- Flink CDC MongoDB Connector 的實現原理和使用實踐MongoDB
- MongoDB 副本集原理及管理MongoDB
- 圖解MongoDB叢集部署原理(3)圖解MongoDB
- MongoDB 儲存引擎與內部原理MongoDB儲存引擎
- MongoDB和Redis的使用MongoDBRedis
- MongoDB 資料庫管理和開發:Navicat for MongoDB macMongoDB資料庫Mac
- MongoDB原理:複製集狀態同步機制MongoDB
- CSDN周賽第48期:贏《MongoDB核心原理與實踐》和定製周邊MongoDB
- CSDN周賽第34期:贏《MongoDB核心原理與實踐》和定製周邊MongoDB
- 快速掌握mongoDB(一)——mongoDB安裝部署和常用shell命令MongoDB
- mongodb資料庫使用03、python和mongodb的互動MongoDB資料庫Python
- MongoDB和pymongo自用手冊MongoDB
- 【五分鐘瞭解MongoDB】Change Stream 和MongoDB 4.xMongoDB
- MongoDB和資料流:使用MongoDB作為Kafka消費者MongoDBKafka
- mongodb和nodejs mongoose使用詳解MongoDBNodeJS
- 使用Golang和MongoDB構建微服務GolangMongoDB微服務
- mongodb macos 下的安裝和使用MongoDBMac
- 快速掌握mongoDB(二)——聚合管道和MapReduceMongoDB
- 初識 MongoDB 和 .NET Core 入門MongoDB
- mongodb和hbase的簡單比較MongoDB
- mongodb的安裝和啟動方法MongoDB
- 使用Golang和MongoDB構建 RESTful APIGolangMongoDBRESTAPI
- Mssql和Mongodb區別是什麼SQLMongoDB
- mongodb和mysql有什麼區別MongoDBMySql
- Node學習筆記 Mongodb 和 Mongoose筆記MongoDB
- mongodb建立索引和刪除索引和背景索引backgroundMongoDB索引
- mongodb和python互動遇到的錯誤MongoDBPython
- 如何使用m工具安裝和管理MongoDBMongoDB
- node.js和MongoDB學習網址Node.jsMongoDB
- 在Red Hat和Centos上安裝MongoDBCentOSMongoDB
- MongoDB記憶體使用分析和優化MongoDB記憶體優化
- Mongodb資料同步和主從切換MongoDB
- Mybatis原理和SqlSessionMyBatisSQLSession
- windows下安裝MongoDB擴充套件和配置WindowsMongoDB套件
- MongoDB 最佳實踐和場景避坑指南MongoDB
- MongoDB中的完整和部分文字搜尋MongoDB
- mysql和mongodb替換欄位中某字元MySqlMongoDB字元