mongodb 事务_MongoDB 事务 — 基础入门篇
MongoDB 單文檔原生支持原子性,也具備事務的特性,但是我們說起事務,通常是指在多文檔中的實現,因此,MongoDB 在 4.0 版本支持了多文檔事務,4.0 對應于復制集的多表、多行,后續又在 4.2 版本支持了分片集的多表、多行事務操作。
事務四大特性
原子性(Atomicity):事務必須是原子工作單元,對于其數據修改,要么全執行,要么全不執行。類似于 Redis 中我通常使用 Lua 腳本來實現多條命令操作的原子性。
一致性(Consistency):事務在完成時,必須使所有的數據都保持一致狀態。
隔離性(Isolation):由并發事務所做的修改必須與任何其他并發事務所作的修改隔離(簡而言之:一個事務執行過程中不應受其它事務影響)。
持久性(Durability):事務完成之后,對于系統的影響是永久性的。
Read Concern/Write Concern/Read Preference
在事務操作中會分別使用到 readConcern、writeConcern、readPreference 這幾個選項,用于控制 Session 的行為,下面分別予以介紹。
事務和 Write Concern
事務使用事務級別的 writeConcern 來提交寫操作,決定一個事務的寫入成功與否要看 writeConcern 選項設置了幾個節點,默認情況下為 1。
幾個選項值:
- w:0 設置為 0 無需關注寫入成功與否。
- w:1 ~ 任意節點數 自定義節點數設置,復制集中不得大于最大節點數。默認情況下為 1,表示寫入到 Primary 節點就開始往客戶端發送確認寫入成功。
- w:"majority" 大多數節點成功原則,例如一個復制集 3 個節點,2 個節點成功就認為本次寫入成功。
- w:"all" 所以節點都成功,才認為寫入成功。
- j:true 默認情況 j:false,寫操作到達內存算作完成。如果設置為 j:true,寫操作只有到達 journal 文件才算成功。
- wtimeout: 寫入超時實踐
設置示例:
writeConcern: {w:"majority" // 大多數原則
j:true,
wtimeout: 5000,
}
JavaScript 使用示例:
db.user.insert({name: "Jack"}, {writeConcern: {w: "majority"}})建議
對于重要數據可以應用 w:"majority" 設置,普通數據 w:1 設置則可以保證性能最佳,w 設置的節點數越多,等待的延遲也就越大,如果 w 等于總節點數,一旦其中某個節點出現故障就會導致整個寫入失敗,也是有風險的。
docs.mongodb.com/manual/reference/write-concern/?spm=a2c4e.10696291.0.0.68d519a4ob3Yya
事務和 Read Preference
在一個事務操作中使用事務級別的 readPreference 來決定讀取時從哪個節點讀取。可方便的實現讀寫分離、就近讀取策略。
可選值以下 5 個:
- primary 只從主節點讀取,默認值。
- primaryPreferred 優先選擇主節點,不可用時選擇從節點
- secondary 只在從節點讀取
- secondaryPreferred 優先在從節點讀取,從節點不可用時選擇主節點。
- nearest 選擇附近節點
場景選擇
- primary/primaryPreferred:適合于數據實時性要求較高的場景,例如,訂單創建完畢直接跳轉到訂單詳情,如果選擇從節點讀取,可能會造成主節點數據寫入之后,從節點還未復制的情況,因為復制過程是一個異步的操作。
- secondary/secondaryPreferred:適應用于數據實時性要求不高的場景,例如,報表數據、歷史訂單。還可以減輕對主節點的壓力。
使用示例
- 鏈接字符串配置:
- Mongo Shell:
測試時可借助 db.fsyncUnlock() 對從節點鎖定,僅主節點寫入數據。
docs.mongodb.com/manual/core/read-preference/#replica-set-read-preference
事務和 Read Concern
MongoDB 3.2 引入了 readConcern 來決定讀取的策略,但是與 readPreference 不同,readPreference 決定從哪個節點讀取,readConcern 決定該節點的哪些數據是可讀的。主要保證事務中的隔離性,避免臟讀。
可選值
- available:讀取所有可用的數據。
- local:僅讀取當前分片的數據。
- majority:讀取在大多數節點上提交完成的數據。
- snapshot:讀取最近快照中的數據。
更新配置項
在啟動 Mongod 實例時,指定 --enableMajorityReadConcern 選項或在配置文件中配置
enableMajorityReadConcern=true重新啟動實例,Mongo shell 登陸實例,使用 db._adminCommand( {getCmdLineOpts: 1}) 查看配置,可以看到在復制集中會多出一個配置,說明配置成功。
{...
"parsed" : {
"replication" : {
"enableMajorityReadConcern" : true, // 變化之處
"oplogSizeMB" : 1024,
"replSet" : "May"
},
},
}
使用示例
db.user.find().readConcern("majority")readConcern 總結
MongoDB 的 readConcern 默認情況下是臟讀,例如,用戶在主節點讀取一條數據之后,該節點未將數據同步至其它從節點,就因為異常掛掉了,待主節點恢復之后,將未同步至其它節點的數據進行回滾,就出現了臟讀。
readConcern 級別的 majority 可以保證讀到的數據已經落入到大多數節點。所以說保證了事務的隔離性,所謂隔離性也是指事務內的操作,事務外是看不見的。
readConcern 參考
- docs.mongodb.com/manual/reference/read-concern/
- MongoDB readConcern 原理解析
讀寫分離實踐
一個典型的應用場景是用戶寫入訂單數據(數據寫入 Primary),立即調用查詢接口,由于采用讀寫分離模式,鏈接字符串設置 readPreference=secondaryPreferred 訂單寫入主節點之后并不能保證數據立即同步到從節點,若此時直接由從節點讀取數據, 偶爾會出現訂單數據無法找到,用戶就會感覺很奇怪,明明下了訂單,卻又查找不到,造成一些異常訂單。
一種導致下單之后再次查找丟失訂單的的寫法如下:
db.order.insert({"id": "123456789"})db.order.find({"id": "123456789"}).readPref("secondaryPreferred")
解決方法一:
設置 readPreference=primary,將復制集的節點讀取由從節點轉換為主節點。
這種方式一個缺點是數據量大了之后會增加主節點的壓力,也就沒有了主從分離的模式。
解決方法二:
使用 writeConcern、readConcern 組合來解決,即保證讀寫分離模式,也保證了數據的一致性。
// 寫入時保證大多數節點寫入成功db.order.insert({"id": "123456789"}, {writeConern: {w: "majority"}})
// 讀取時保證這條數據已在大多數節點存在
db.order.find({"id": "123456789"}).readPref("secondaryPreferred").readConcern("majority")
本文是對 MogoDB 事務的一個初步了解,Read Concern/Write Concern/Read Preference 這些在后續事務實踐中都會應用,希望大家可以事先進行一個了解,在接下來的一篇文章中,我會介紹 MongoDB 的事務應該如何應用,同時結合 Node.js 進行實踐說明,歡迎關注!
Reference
- http://mongoing.com/archives/5476
- https://docs.mongodb.com/manual/core/transactions/
總結
以上是生活随笔為你收集整理的mongodb 事务_MongoDB 事务 — 基础入门篇的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python本地镜像源搭建_【Pytho
- 下一篇: mongodb 事务_MongoDB4