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