MongoDB讀數據策略
MongoDB是開源文檔型NoSQL數據庫,它的數據模型靈活,具有高擴展性、高可用性、易用性等特點,能夠存儲半結構化的數據,并且有豐富的查詢語言和索引類型,當前MongoDB已廣泛的用在各企業的核心業務系統中。MongoDB也是db-engines排名最高的非關系型數據庫。
圖片來源:db-engines
在MongoDB讀取數據主要是受read concern(讀策略)、read preference (讀偏好設置 )兩個參數控制,其中readconcern決定在讀取副本集和分片集數據時的一致性和隔離性,而readpreference 決定客戶端驅動讀取哪個數據節點的數據。它們的配合使用,可以提高MongoDB 集群的性能,以及在數據一致性和讀性能上做平衡。
readconcern 一致性讀策略
Readconcern 主要解決臟讀問題,從3.2版本后開始支持。比如PSA集群,用戶從 MongoDB 的 primary 上讀取數據后,這條數據并沒有同步從數節點,然后 primary 就故障了。此時不同的Readconcern值,MongoDB 返回數據的處理方式是不同的。
Readconcern有幾個不同的參數,分別是local、available、majority、linearizable、snapshot ,數據庫在這些參數下的一致性是由弱到強遞增的。
?幾種模式介紹?
- Local
表示讀取的數據從實例中返回數據,但不保證數據是否被持久化(即可能被回滾)。該參數默認值為local。
- Available
表示讀取的數據從實例中返回數據,但不保證數據是否被持久化(即可以回滾)。乍一看available和local沒有啥區別,對于副本集架構兩者是相同的,主要區別場景是分片群集。在分片集群下,數據遷移會出現孤兒文檔(orphaned document),available模式可以從延遲最低的節點獲取數據,而local則直接返回數據。該參數是3.6版的新功能。
- Majority
表示讀取返回多數副本集成員已確認的數據,這個數據是持久化的不會被回滾。需要注意,在Majority下只能保證讀到的數據“不會發生回滾”,但并不能保證讀到的數據一定是最新的,官方也明確做了說明。
Regardless of the read concern level, the most recent data on a node may not reflect the most recent version of the data in the system。
- linearizable
線性讀取數據。根據官方資料翻譯成中文:該查詢返回的數據,反映了在讀取操作開始之前完成的所有成功的多數確認寫入。查詢可能會等待并發執行的寫操作傳播到大多數副本集成員,然后返回結果。也就是在這種模式下,讀可能需要等待其他寫操作完成。
- snapshot
從最新的快照中讀取數據。如果事務不是因果一致的會話的一部分,并且數據的寫入參數writeconcern 值也是majority下,那將從多數提交數據的快照中讀取數據。
一般在生產推薦配置成Majority,這種模式是在數據安全和性能上相對平衡的選擇,但是使用Majority也有要求和問題。首先它只支持WiredTiger引擎,其次需要寫入參數writeconcern 也是majority 才會生效,最后在Majority下也不能完全保證解決了臟讀問題。
?Majority 實現?
MongoDB 在readconcern majority 下,數據庫會起一個單獨的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發生變化時,會通過命令將 oplog 進度立即通知給 primary,同時節點間的心跳消息里也會包含最新 oplog 的信息。這樣primary 節點能很快知道數據是否已經同步到大多數節點的,并更新 snapshot 的狀態。比如當t2已經寫入到大多數據節點時,snapshot1、snapshot2都可以更新為 commited 狀態。
對于secondary 節點來說,在拉取 oplog 時,primary 節點會將“最新的數據已同步到大多數節點的”的信息返回給 secondary 節點,然后secondary 節點通過這個oplog時間戳來更新自身的 snapshot 狀態。
readpreference 讀偏好設置
MongoDB 讀控制策略除了readconcern策略外,還有readpreference 。它主要控制數據庫客戶端驅動從哪個節點讀取數據。這個特性可以方便地實現讀寫分離、就近讀取等策略。
readpreference 是由三部分組成,分別是mode、maxStalenessSeconds 、tag set,其中mode支持五種類型,分別是:primary、primaryPreferred、Secondary、secondaryPreferred、nearest,我們先看幾種模式的具體含義。
?幾種模式介紹?
- primary
默認模式。讀操作只在主節點,如果主節點不可用,報錯或者拋出異常。這種策略適用于應用程序需要嚴格的一致性,但可用性不是首要考慮因素的情況。
- primaryPreferred
大多情況下讀操作在主節點,如果主節點不可用,如故障轉移,讀操作在從節點。
- secondary
僅從secondary節點中讀取,如果secondary節點不可用,讀將會報錯。
- secondaryPreferred
大多情況下讀操作在從節點,特殊情況(如沒有從節點)讀操作在主節點。
- nearest
根據指定的延遲閾值,隨機地從符合條件的數據節點中讀取操作,不管該節點是主還是從節點。
?maxStalenessSeconds?
MongoDB 3.4 以后版本新增maxStalenessSeconds參數。集群的從節點可能因為網絡阻塞、磁盤吞吐低、長時間執行等原因,使從節點落后于主節點。當從節點延遲時間超過了該參數定義的值,客戶端不會從該節點讀取數據。maxStalenessSeconds 不能與primary 模式兼容,只能在其他四種模式下使用。
當選擇了使用該參數控制讀取數據,客戶端會通過比較從節點和主節點的最后一次寫時間來估計從節點的過期程度。客戶端會把連接指向小于等于maxStalenessSeconds的從節點。另外,需要注意maxStalenessSeconds最小值是90秒,如果小于該值將報錯。
You must specify a maxStalenessSeconds value of 90 seconds or longer: specifying a smaller maxStalenessSeconds value will raise an error.
?標簽集?
如果一個復制集中的成員有tag,就可以通過下面的辦法讀取到帶有具體標簽的成員上。例如,如果某個節點有這樣的成員標簽:
?訪問案例?
總結上面的內容,可以通過下面三種方式去定義不同的readpreference策略。
總結
通過上文介紹,我們知道MongoDB讀數據策略,有readconcern和readpreference兩個重要的概念。其中readconcern是讀數據時的數據一致性級別,它決定了決定讀取數據時讀到什么樣的數據。通常結合可用性和性能,會將readconcern設置為majority。而readpreference決定讀哪個節點的數據,主要用于實現讀寫分離上。另外,MongoDB還提供了其他的配置選項,如寫數據策略(writeconcern)這將在后面的文章中介紹。
作者介紹
司馬遼太杰是 NineData 工程師。NineData 向企業和個人提供高效、安全的數據庫SQL開發、數據庫備份、數據復制/遷移/集成、數據對比等能力的產品,它是開箱即用的SaaS服務,可以快速提升企業SQL開發效率,保障企業數據安全。近期,NineData 即將會支持MongoDB、Redis等NoSQL數據庫。NineData 官網地址:??https://ninedata.cloud??。
本文轉載自微信公眾號「云數據庫技術」,可以通過以下二維碼關注。轉載本文請聯系云數據庫技術公眾號。