MongoDB分布式原理以及read-preference和readConcern解决读写一致性问题
MongoDB詞匯表:
https://docs.mongodb.com/manual/reference/glossary/#term-replica-set
?
MongoDB分布式原理
primary
In a?replica set, the primary is the member that receives all write operations. See?Primary.
在副本集中,主庫是接收所有寫操作的節(jié)點(diǎn)。
secondary
A?replica set?member that replicates the contents of the master database. Secondary members may handle read requests, but only the?primary?members can handle write operations. See?Secondaries.
一個(gè)副本集,其復(fù)制所述主數(shù)據(jù)庫中的內(nèi)容。次節(jié)點(diǎn):讀請(qǐng)求。主庫:寫操作。
復(fù)制
允許多個(gè)數(shù)據(jù)庫服務(wù)器共享相同數(shù)據(jù)的功能,從而確保冗余并促進(jìn)負(fù)載平衡。請(qǐng)參見復(fù)制。
https://docs.mongodb.com/manual/replication/#replication-auto-failover
復(fù)制提供冗余并提高?數(shù)據(jù)可用性。使用不同數(shù)據(jù)庫服務(wù)器上的多個(gè)數(shù)據(jù)副本,復(fù)制可提供一定程度的容錯(cuò)能力,以防止丟失單個(gè)數(shù)據(jù)庫服務(wù)器。
在某些情況下,復(fù)制可以提供更大的讀取容量,因?yàn)榭蛻舳丝梢詫⒆x取操作發(fā)送到不同的服務(wù)器。在不同數(shù)據(jù)中心中維護(hù)數(shù)據(jù)副本可以提高數(shù)據(jù)本地性和分布式應(yīng)用程序的可用性。您還可以維護(hù)其他副本以用于專用目的,例如災(zāi)難恢復(fù),報(bào)告或備份。
異步復(fù)制
輔助節(jié)點(diǎn)復(fù)制主節(jié)點(diǎn)的操作日志,并將操作異步應(yīng)用于其數(shù)據(jù)集。通過使次要節(jié)點(diǎn)的數(shù)據(jù)集反映主要節(jié)點(diǎn)的數(shù)據(jù)集,即使一個(gè)或多個(gè)成員失敗,副本集也可以繼續(xù)運(yùn)行。
故障轉(zhuǎn)移
在發(fā)生故障時(shí)允許副本集的輔助成員成為主庫成的過程。請(qǐng)參閱自動(dòng)故障轉(zhuǎn)移。
如果主要節(jié)點(diǎn)不可用,則符合條件的次要節(jié)點(diǎn)將進(jìn)行選舉以自行選舉新的主要節(jié)點(diǎn)。
自動(dòng)故障轉(zhuǎn)移
時(shí)機(jī):當(dāng)主節(jié)點(diǎn)與集合中的其他成員的通信electionTimeoutMillis時(shí)間超過配置的時(shí)間段(默認(rèn)為10秒)時(shí)。
由于突發(fā)的網(wǎng)絡(luò)延遲等因素,群集可能會(huì)頻繁選舉,即使該主節(jié)點(diǎn)處于健康狀態(tài)也是如此。
?
方式:合格的輔助節(jié)點(diǎn)將要求選舉以提名自己為新的主節(jié)點(diǎn)。群集嘗試完成新主數(shù)據(jù)庫的選擇并恢復(fù)正常操作。
?
副本集無法處理寫入操作,直到選舉成功完成。
如果將副本集配置為在主副本處于脫機(jī)狀態(tài)時(shí)在次副本上運(yùn)行,則副本集可以繼續(xù)提供讀取查詢?。
應(yīng)用程序連接邏輯應(yīng)包括對(duì)自動(dòng)故障轉(zhuǎn)移和后續(xù)選舉的容忍度。
從MongoDB 3.6開始,MongoDB驅(qū)動(dòng)程序客戶端可以檢測到主數(shù)據(jù)庫的丟失,并一次自動(dòng) 重試某些寫入操作,從而提供了自動(dòng)故障轉(zhuǎn)移和選擇的其他內(nèi)置處理。
https://docs.mongodb.com/manual/core/retryable-writes/#retryable-writes
?
選舉
副本集的成員在啟動(dòng)時(shí)和發(fā)生故障時(shí)選擇主庫的過程。請(qǐng)參閱?副本集選擇。
https://docs.mongodb.com/manual/core/replica-set-elections/#replica-set-elections
?
最終一致性
分布式系統(tǒng)的屬性,允許對(duì)系統(tǒng)的更改逐漸傳播。在數(shù)據(jù)庫系統(tǒng)中,這意味著不需要可讀成員始終反映最新的寫入。
====================
readPreference和readConcern配合使用
-
readPreference?主要控制客戶端 Driver 從復(fù)制集的哪個(gè)節(jié)點(diǎn)讀取數(shù)據(jù),這個(gè)特性可方便的實(shí)現(xiàn)讀寫分離、就近讀取等策略。
primary?只從 primary 節(jié)點(diǎn)讀數(shù)據(jù),這個(gè)是默認(rèn)設(shè)置primaryPreferred?優(yōu)先從 primary 讀取,primary 不可服務(wù),從 secondary 讀secondary?只從 scondary 節(jié)點(diǎn)讀數(shù)據(jù)secondaryPreferred?優(yōu)先從 secondary 讀取,沒有 secondary 成員時(shí),從 primary 讀取nearest?根據(jù)網(wǎng)絡(luò)距離就近讀取
-
readConcern?決定到某個(gè)讀取數(shù)據(jù)時(shí),能讀到什么樣的數(shù)據(jù)。
local?能讀取任意數(shù)據(jù),這個(gè)是默認(rèn)設(shè)置majority?只能讀取到『成功寫入到大多數(shù)節(jié)點(diǎn)的數(shù)據(jù)』
========================
read-preference
官網(wǎng)地址:https://docs.mongodb.com/manual/core/read-preference/
讀取首選項(xiàng)描述了MongoDB客戶端如何將讀取操作路由到副本集的成員。
默認(rèn)情況下,應(yīng)用程序?qū)⑵渥x取操作定向到副本集中的 主要成員(即讀取首選項(xiàng)模式“主要”)。但是,客戶端可以指定讀取首選項(xiàng),以將讀取操作發(fā)送到輔助對(duì)象。
| 讀取首選項(xiàng)模式 | 描述 |
|---|---|
primary | 默認(rèn)模式。所有操作均從當(dāng)前副本集primary讀取?。 包含讀取操作的多文檔事務(wù)必須使用讀取首選項(xiàng) |
primaryPreferred | 在大多數(shù)情況下,操作從主服務(wù)器讀取,但如果不可用,則從輔助?成員讀取操作。 |
secondary | 所有操作均從副本集的輔助成員讀取。 |
secondaryPreferred | 在大多數(shù)情況下,操作會(huì)從輔助?成員讀取,但如果沒有輔助成員可用,則操作會(huì)從primary讀取。 |
nearest | 從副本集的成員讀取的操作具有最小的網(wǎng)絡(luò)延遲,而與成員的類型無關(guān)。 |
?
==================
readConcern
官網(wǎng)地址:https://docs.mongodb.com/manual/reference/read-concern/
該readConcern選項(xiàng)使您可以控制從副本集和副本集分片讀取的數(shù)據(jù)的一致性和隔離性。
通過有效使用寫入關(guān)注點(diǎn)和讀取關(guān)注點(diǎn),您可以適當(dāng)?shù)卣{(diào)整一致性和可用性保證的級(jí)別,例如等待更強(qiáng)的一致性保證,或者放寬一致性要求以提供更高的可用性。
為MongoDB 3.2或更高版本更新的MongoDB驅(qū)動(dòng)程序支持指定讀取關(guān)注。
?
readConcern 的是為了在于解決臟讀問題,用戶從 MongoDB 的 primary 上讀的數(shù)據(jù)并沒有同步到大多數(shù)節(jié)點(diǎn),然后 primary 宕機(jī)恢復(fù), primary節(jié)點(diǎn)會(huì)將未同步到大多數(shù)節(jié)點(diǎn)的數(shù)據(jù)回滾,導(dǎo)致用戶讀到了臟數(shù)據(jù)。
當(dāng)指定 readConcern 級(jí)別為majority ,能保證用戶讀到的數(shù)據(jù)已經(jīng)寫入到大多數(shù)節(jié)點(diǎn),而這樣的數(shù)據(jù)肯定不會(huì)發(fā)生回滾,避免了臟讀的問題。
需要注意的是,readConcern 只是保證讀到的數(shù)據(jù)不會(huì)發(fā)生回滾,但并不能保證讀到的數(shù)據(jù)最新。
參考官網(wǎng):
誤區(qū):?majority并非從多節(jié)點(diǎn)讀取,依然是單節(jié)點(diǎn)讀取。
readConcern 原理
snapshot 0,1,2,3......N的狀態(tài)是committed/uncommitted
同步到大多數(shù)節(jié)點(diǎn)時(shí),對(duì)應(yīng)的snapshot會(huì)標(biāo)記為commmited。
用戶讀取:讀最新的 commited 狀態(tài)的 snapshot,這樣就保證了讀到的數(shù)據(jù)是已經(jīng)同步到大多數(shù)節(jié)點(diǎn)。
secondary節(jié)點(diǎn)在自身oplog發(fā)生變化會(huì)同步信息到primary。
primary節(jié)點(diǎn)統(tǒng)計(jì)超過半數(shù)的節(jié)點(diǎn)的同步信息就修改該snapshot為uncommitted->commited。
同時(shí)secondary拉取oplog的同時(shí)從primary節(jié)點(diǎn)得到最新一條已經(jīng)同步到大多數(shù)節(jié)點(diǎn)的oplog,更新自身的 snapshot 狀態(tài)。
?
參考:
https://yq.aliyun.com/articles/60553
https://yq.aliyun.com/articles/663931
readConcern 主要用于跟 mongos 與 config server 的交互上
當(dāng)寫入新文檔時(shí),mongos 從config server 上獲取集合的路由表本地,如寫入shardX的文檔,則請(qǐng)求被路由到shardX上寫入。
mongos 從 config server 上獲取到路由表后,會(huì)緩存在本地內(nèi)存,避免每次寫入/查詢都去 config server 上取表。
mongos 在寫入時(shí),會(huì)帶上自身緩存的路由表版本,當(dāng)請(qǐng)求到達(dá) shard后,shard 發(fā)現(xiàn) mongos 的路由表版本比自己的低,則說明路由表已經(jīng)發(fā)生過更新,這時(shí) mongos 會(huì)重新到 config server 上取最新的路由表,然后按新的路由表來寫入。
https://yq.aliyun.com/articles/58689
Mongos本身并不持久化數(shù)據(jù),Sharded cluster所有的元數(shù)據(jù)都會(huì)存儲(chǔ)到Config Server,而用戶的數(shù)據(jù)則會(huì)分散存儲(chǔ)到各個(gè)shard。Mongos啟動(dòng)后,會(huì)從config server加載元數(shù)據(jù),開始提供服務(wù),將用戶的請(qǐng)求正確路由到對(duì)應(yīng)的Shard。
https://yq.aliyun.com/articles/32434
================
Read Concern?"majority"
https://docs.mongodb.com/manual/reference/read-concern-majority/index.html
考慮以下寫入三個(gè)成員副本集的操作Write0的時(shí)間軸:
注意 為了簡化,該示例假定:
Write0之前的所有寫操作已成功復(fù)制到所有成員。
Writeprev是Write0之前的上一次寫入。
Write0之后未發(fā)生其他寫操作。
然后,下表總結(jié)了在時(shí)間T具有“多數(shù)”讀取關(guān)注的讀取操作將看到的數(shù)據(jù)狀態(tài)。
?
最新數(shù)據(jù)不在大部分機(jī)器:?
?
?
臟數(shù)據(jù):
總結(jié)
以上是生活随笔為你收集整理的MongoDB分布式原理以及read-preference和readConcern解决读写一致性问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 女人的泪是什么歌呢?
- 下一篇: Apache Hudi的写时复制和读时合