MongoDB有主從復(fù)制和副本集兩種復(fù)制模式,主從復(fù)制最大的問(wèn)題就是無(wú)法自動(dòng)故障轉(zhuǎn)移,MongoDB副本集則解決了主從模式無(wú)法自動(dòng)故障轉(zhuǎn)義的缺點(diǎn)。
MongoDB副本集是將數(shù)據(jù)同步在多個(gè)服務(wù)器的過(guò)程。復(fù)制提供了數(shù)據(jù)的冗余備份,并在多個(gè)服務(wù)器上存儲(chǔ)數(shù)據(jù)副本,提高了數(shù)據(jù)的可用性, 并可以保證數(shù)據(jù)的安全性,用于災(zāi)難恢復(fù),無(wú)需停機(jī)維護(hù),分布式讀取數(shù)據(jù)。
特征
- N 個(gè)節(jié)點(diǎn)的集群
- 任何節(jié)點(diǎn)可作為主節(jié)點(diǎn)
- 所有寫(xiě)入操作都在主節(jié)點(diǎn)上
- 自動(dòng)故障轉(zhuǎn)移(如果主節(jié)點(diǎn)10s以上與其他節(jié)點(diǎn)失去通信,其他節(jié)點(diǎn)將會(huì)選舉新的節(jié)點(diǎn)作為主節(jié)點(diǎn))
- 自動(dòng)恢復(fù)
MongoDB的副本集在主機(jī)宕機(jī)后,副本會(huì)接管主節(jié)點(diǎn)成為主節(jié)點(diǎn),不會(huì)出現(xiàn)宕機(jī)的情況。 - 副本節(jié)點(diǎn)同步主節(jié)點(diǎn)操作是異步的,會(huì)導(dǎo)致副本集無(wú)法返回最新的數(shù)據(jù)給客戶(hù)端程序。
副本集復(fù)制原理
mongodb的復(fù)制至少需要兩個(gè)節(jié)點(diǎn)。其中一個(gè)是主節(jié)點(diǎn),負(fù)責(zé)處理客戶(hù)端請(qǐng)求,其余的都是從節(jié)點(diǎn),負(fù)責(zé)復(fù)制主節(jié)點(diǎn)上的數(shù)據(jù)。
主節(jié)點(diǎn)記錄在其上的所有操作oplog,從節(jié)點(diǎn)定期輪詢(xún)主節(jié)點(diǎn)獲取這些操作,然后對(duì)自己的數(shù)據(jù)副本執(zhí)行這些操作,從而保證從節(jié)點(diǎn)的數(shù)據(jù)與主節(jié)點(diǎn)一致。
oplog 具有冪等性,即無(wú)論執(zhí)行幾次其結(jié)果一致,這個(gè)比 mysql 的二進(jìn)制日志更好用

- 副本集使用的是 n 個(gè) mongod 節(jié)點(diǎn),構(gòu)建具備自動(dòng)的容錯(cuò)功能(auto-failover),自動(dòng)恢復(fù)的(auto-recovery)的高可用方案。
- 對(duì)于副本集中的Secondary節(jié)點(diǎn)默認(rèn)是不可讀的。
- 可以使用副本集來(lái)實(shí)現(xiàn)讀寫(xiě)分離。通過(guò)在連接時(shí)指定或者在主庫(kù)指定 slave,由Secondary 來(lái)分擔(dān)讀的壓力,Primary只承擔(dān)寫(xiě)操作。
- 主實(shí)例接受客戶(hù)的寫(xiě)操作,副本集只能有一個(gè)主實(shí)例,因?yàn)闉榱司S持?jǐn)?shù)據(jù)一致性,只有一個(gè)實(shí)例可寫(xiě),主實(shí)例的日志保存在oplog。
集群中的各節(jié)點(diǎn)還會(huì)通過(guò)傳遞心跳信息來(lái)檢測(cè)各自的健康狀況。當(dāng)主節(jié)點(diǎn)故障時(shí),多個(gè)從節(jié)點(diǎn)會(huì)觸發(fā)一次 新的選舉操作,并選舉其中的一個(gè)成為新的主節(jié)點(diǎn)(通常誰(shuí)的優(yōu)先級(jí)更高,誰(shuí)就是新的主節(jié)點(diǎn)),心跳信息默認(rèn)每 2 秒傳遞一次

心跳檢測(cè):
整個(gè)集群需要保持一定的通信才能知道哪些節(jié)點(diǎn)活著哪些節(jié)點(diǎn)掛掉。mongodb節(jié)點(diǎn)會(huì)向副本集中的其他節(jié)點(diǎn)每?jī)擅刖蜁?huì)發(fā)送一次pings包,如果其他節(jié)點(diǎn)在10秒鐘
之內(nèi)沒(méi)有返回就標(biāo)識(shí)為不能訪問(wèn)。每個(gè)節(jié)點(diǎn)內(nèi)部都會(huì)維護(hù)一個(gè)狀態(tài)映射表,表明當(dāng)前每個(gè)節(jié)點(diǎn)是什么角色、日志時(shí)間戳等關(guān)鍵信息。如果是主節(jié)點(diǎn),除了維護(hù)映射表外還需要檢查自己能否和集群中內(nèi)大部分節(jié)點(diǎn)通訊,如果不能則把自己降級(jí)為secondary只讀節(jié)點(diǎn)。
副本集包括三種節(jié)點(diǎn):主節(jié)點(diǎn)、從節(jié)點(diǎn)、仲裁節(jié)點(diǎn)。
1)主節(jié)點(diǎn)負(fù)責(zé)處理客戶(hù)端請(qǐng)求,讀、寫(xiě)數(shù)據(jù), 記錄在其上所有操作的 oplog;
2)從節(jié)點(diǎn)定期輪詢(xún)主節(jié)點(diǎn)獲取這些操作,然后對(duì)自己的數(shù)據(jù)副本執(zhí)行這些操作,從而保證從節(jié)點(diǎn)的數(shù)據(jù)與主節(jié)點(diǎn)一致。默認(rèn)情況下,從節(jié)點(diǎn)不支持外部讀取,但可以設(shè)置;
副本集的機(jī)制在于主節(jié)點(diǎn)出現(xiàn)故障的時(shí)候,余下的節(jié)點(diǎn)會(huì)選舉出一個(gè)新的主節(jié)點(diǎn),從而保證系統(tǒng)可以正常運(yùn)行。
3)仲裁節(jié)點(diǎn)不復(fù)制數(shù)據(jù),僅參與投票。由于它沒(méi)有訪問(wèn)的壓力,比較空閑,因此不容易出故障。由于副本集出現(xiàn)故障的時(shí)候,存活的節(jié)點(diǎn)必須大于副本集節(jié)點(diǎn)總數(shù)的一半,否則無(wú)法選舉主節(jié)點(diǎn),或者主節(jié)點(diǎn)會(huì)自動(dòng)降級(jí)為從節(jié)點(diǎn),整個(gè)副本集變?yōu)橹蛔x。因此,增加一個(gè)不容易出故障的仲裁節(jié)點(diǎn),可以增加有效選票,降低整個(gè)副本集不可用的風(fēng)險(xiǎn)。仲裁節(jié)點(diǎn)可多于一個(gè)。也就是說(shuō)只參與投票,不接收復(fù)制的數(shù)據(jù),也不能成為活躍節(jié)點(diǎn)。
官方推薦MongoDB副本節(jié)點(diǎn)最少為3臺(tái), 建議副本集成員為奇數(shù),最多12個(gè)副本節(jié)點(diǎn),最多7個(gè)節(jié)點(diǎn)參與選舉。
限制副本節(jié)點(diǎn)的數(shù)量,主要是因?yàn)橐粋€(gè)集群中過(guò)多的副本節(jié)點(diǎn),增加了復(fù)制的成本,反而拖累了集群的整體性能。 太多的副本節(jié)點(diǎn)參與選舉,也會(huì)增加選舉的時(shí)間。而官方建議奇數(shù)的節(jié)點(diǎn),是為了避免腦裂的發(fā)生。
副本集工作流程
備份節(jié)點(diǎn)的工作原理過(guò)程可以大致描述為,備份節(jié)點(diǎn)定期輪詢(xún)主節(jié)點(diǎn)上的數(shù)據(jù)操作,然后對(duì)自己的數(shù)據(jù)副本進(jìn)行這些操作,從而保證跟主節(jié)點(diǎn)的數(shù)據(jù)同步。至于主節(jié)點(diǎn)上的所有數(shù)據(jù)庫(kù)狀態(tài)改變 的操作,都會(huì)存放在一張?zhí)囟ǖ南到y(tǒng)表中。備份節(jié)點(diǎn)則是根據(jù)這些數(shù)據(jù)進(jìn)行自己的數(shù)據(jù)更新。
oplog
上面提到的數(shù)據(jù)庫(kù)狀態(tài)改變的操作,稱(chēng)為 oplog(operation log,主節(jié)點(diǎn)操作記錄)。oplog 存儲(chǔ)在 local 數(shù)據(jù)庫(kù)的"oplog.rs"表中。副本集中備份節(jié)點(diǎn)異步的從主節(jié)點(diǎn)同步 oplog,然后重新 執(zhí)行它記錄的操作,以此達(dá)到了數(shù)據(jù)同步的作用。
關(guān)于 oplog 有幾個(gè)注意的地方:
1)oplog 只記錄改變數(shù)據(jù)庫(kù)狀態(tài)的操作
2)存儲(chǔ)在 oplog 中的操作并不是和主節(jié)點(diǎn)執(zhí)行的操作完全一樣,例如"$inc"操作就會(huì)轉(zhuǎn)化為"$set"操作
3)oplog 存儲(chǔ)在固定集合中(capped collection),當(dāng) oplog 的數(shù)量超過(guò) oplogSize,新的操作就會(huì)覆蓋就的操作
數(shù)據(jù)同步
在副本集中,有兩種數(shù)據(jù)同步方式:
1)initial sync(初始化):這個(gè)過(guò)程發(fā)生在當(dāng)副本集中創(chuàng)建一個(gè)新的數(shù)據(jù)庫(kù)或其中某個(gè)節(jié)點(diǎn)剛從宕機(jī)中恢復(fù),或者向副本集中添加新的成員的時(shí)候,
當(dāng)secondary落后的數(shù)據(jù)量超過(guò)了oplog的大小,這樣也會(huì)被全量復(fù)制。默認(rèn)的,副本集中的節(jié)點(diǎn)會(huì)從離它最近的節(jié)點(diǎn)復(fù)制 oplog 來(lái)同步數(shù)據(jù),這個(gè)最近的節(jié)點(diǎn)可以是 primary 也可以是擁有最新 oplog 副本的 secondary 節(jié)點(diǎn)。該操作一般會(huì)重新初始化備份節(jié)點(diǎn),開(kāi)銷(xiāo)較大。
2)replication(復(fù)制):在初始化后這個(gè)操作會(huì)一直持續(xù)的進(jìn)行著,以保持各個(gè) secondary 節(jié)點(diǎn)之間的數(shù)據(jù)同步。
initial sync
當(dāng)遇到無(wú)法同步的問(wèn)題時(shí),只能使用以下兩種方式進(jìn)行 initial sync 了
1)第一種方式就是停止該節(jié)點(diǎn),然后刪除目錄中的文件,重新啟動(dòng)該節(jié)點(diǎn)。這樣,這個(gè)節(jié) 點(diǎn)就會(huì)執(zhí)行 initial sync
注意:通過(guò)這種方式,sync 的時(shí)間是根據(jù)數(shù)據(jù)量大小的,如果數(shù)據(jù)量過(guò)大,sync 時(shí)間就會(huì)很長(zhǎng),同時(shí)會(huì)有很多網(wǎng)絡(luò)傳輸,可能會(huì)影響其他節(jié)點(diǎn)的工作
2)第二種方式,停止該節(jié)點(diǎn),然后刪除目錄中的文件,找一個(gè)比較新的節(jié)點(diǎn),然后把該節(jié)點(diǎn)目 錄中的文件拷貝到要 sync 的節(jié)點(diǎn)目錄中。
通過(guò)上面兩種方式中的一種,都可以重新恢復(fù)該節(jié)點(diǎn)。不在進(jìn)行截圖了。
副本集管理
1)查看oplog的信息 通過(guò)"db.printReplicationInfo()"命令可以查看 oplog 的信息
字段說(shuō)明:
configured oplog size: oplog 文件大小
log length start to end: oplog 日志的啟用時(shí)間段
oplog first event time: 第一個(gè)事務(wù)日志的產(chǎn)生時(shí)間
oplog last event time: 最后一個(gè)事務(wù)日志的產(chǎn)生時(shí)間
now: 現(xiàn)在的時(shí)間
2)查看 slave 狀態(tài) 通過(guò)"db.printSlaveReplicationInfo()"可以查看 slave 的同步狀態(tài)
當(dāng)插入一條新的數(shù)據(jù),然后重新檢查 slave 狀態(tài)時(shí),就會(huì)發(fā)現(xiàn) sync 時(shí)間更新了
副本集選舉過(guò)程
Mongodb副本集選舉采用的是Bully算法,這是一種協(xié)調(diào)者(主節(jié)點(diǎn))競(jìng)選算法,主要思想是集群的每個(gè)成員都可以聲明它是主節(jié)點(diǎn)并通知其他節(jié)點(diǎn)。別的節(jié)點(diǎn)可以選擇接受這個(gè)聲稱(chēng)或是拒絕并進(jìn)入主節(jié)點(diǎn)競(jìng)爭(zhēng),被其他所有節(jié)點(diǎn)接受的節(jié)點(diǎn)才能成為主節(jié)點(diǎn)。
節(jié)點(diǎn)按照一些屬性來(lái)判斷誰(shuí)應(yīng)該勝出,這個(gè)屬性可以是一個(gè)靜態(tài) ID,也可以是更新的度量像最近一次事務(wù)ID(最新的節(jié)點(diǎn)會(huì)勝出)
副本集的選舉過(guò)程大致如下:
1)得到每個(gè)服務(wù)器節(jié)點(diǎn)的最后操作時(shí)間戳。每個(gè) mongodb 都有 oplog 機(jī)制會(huì)記錄本機(jī)的操作,方便和主服 務(wù)器進(jìn)行對(duì)比數(shù)據(jù)是否同步還可以用于錯(cuò)誤恢復(fù)。
2)如果集群中大部分服務(wù)器 down 機(jī)了,保留活著的節(jié)點(diǎn)都為 secondary 狀態(tài)并停止,不選舉了。
3)如果集群中選舉出來(lái)的主節(jié)點(diǎn)或者所有從節(jié)點(diǎn)最后一次同步時(shí)間看起來(lái)很舊了,停止選舉等待人來(lái)操作。
4)如果上面都沒(méi)有問(wèn)題就選擇最后操作時(shí)間戳最新(保證數(shù)據(jù)是最新的)的服務(wù)器節(jié)點(diǎn)作為主節(jié)點(diǎn)。
副本集選舉的特點(diǎn):
選舉還有個(gè)前提條件,參與選舉的節(jié)點(diǎn)數(shù)量必須大于副本集總節(jié)點(diǎn)數(shù)量的一半(建議副本集成員為奇數(shù)。最多12個(gè)副本節(jié)點(diǎn),最多7個(gè)節(jié)點(diǎn)參與選舉)
如果已經(jīng)小于一半了所有節(jié)點(diǎn)保持只讀狀態(tài)。集合中的成員一定要有大部分成員(即超過(guò)一半數(shù)量)是保持正常在線狀態(tài),3個(gè)成員的副本集,需要至少2個(gè)從屬節(jié)點(diǎn)是正常狀態(tài)。
如果一個(gè)從屬節(jié)點(diǎn)掛掉,那么當(dāng)主節(jié)點(diǎn)down掉 產(chǎn)生故障切換時(shí),由于副本集中只有一個(gè)節(jié)點(diǎn)是正常的,少于一半,則選舉失敗。
4個(gè)成員的副本集,則需要3個(gè)成員是正常狀態(tài)(先關(guān)閉一個(gè)從屬節(jié)點(diǎn),然后再關(guān)閉主節(jié)點(diǎn),產(chǎn)生故障切換,此時(shí)副本集中只有2個(gè)節(jié)點(diǎn)正常,則無(wú)法成功選舉出新主節(jié)點(diǎn))。
副本集數(shù)據(jù)同步過(guò)程
Primary節(jié)點(diǎn)寫(xiě)入數(shù)據(jù),Secondary通過(guò)讀取Primary的oplog得到復(fù)制信息,開(kāi)始復(fù)制數(shù)據(jù)并且將復(fù)制信息寫(xiě)入到自己的oplog。如果某個(gè)操作失敗,則備份節(jié)點(diǎn)
停止從當(dāng)前數(shù)據(jù)源復(fù)制數(shù)據(jù)。如果某個(gè)備份節(jié)點(diǎn)由于某些原因掛掉了,當(dāng)重新啟動(dòng)后,就會(huì)自動(dòng)從oplog的最后一個(gè)操作開(kāi)始同步,同步完成后,將信息寫(xiě)入自己的oplog,由于復(fù)制操作是先復(fù)制數(shù)據(jù),復(fù)制完成后再寫(xiě)入oplog,有可能相同的操作會(huì)同步兩份,不過(guò)MongoDB在設(shè)計(jì)之初就考慮到這個(gè)問(wèn)題,將oplog的同一個(gè)操作執(zhí)行多次,與執(zhí)行一次的效果是一樣的。簡(jiǎn)單的說(shuō)就是:
當(dāng)Primary節(jié)點(diǎn)完成數(shù)據(jù)操作后,Secondary會(huì)做出一系列的動(dòng)作保證數(shù)據(jù)的同步:
1)檢查自己local庫(kù)的oplog.rs集合找出最近的時(shí)間戳。
2)檢查Primary節(jié)點(diǎn)local庫(kù)oplog.rs集合,找出大于此時(shí)間戳的記錄。
3)將找到的記錄插入到自己的oplog.rs集合中,并執(zhí)行這些操作。
副本集的同步和主從同步一樣,都是異步同步的過(guò)程,不同的是副本集有個(gè)自動(dòng)故障轉(zhuǎn)移的功能。其原理是:slave端從primary端獲取日志,然后在自己身上完全順序的執(zhí)行日志所記錄的各種操作(該日志是不記錄查詢(xún)操作的),這個(gè)日志就是local數(shù)據(jù) 庫(kù)中的oplog.rs表,默認(rèn)在64位機(jī)器上這個(gè)表是比較大的,占磁盤(pán)大小的5%,
oplog.rs的大小可以在啟動(dòng)參數(shù)中設(shè) 定:--oplogSize 1000,單位是M。
注意:在副本集的環(huán)境中,要是所有的Secondary都宕機(jī)了,只剩下Primary。最后Primary會(huì)變成Secondary,不能提供服務(wù)。
數(shù)據(jù)同步延遲問(wèn)題
當(dāng)你的用戶(hù)抱怨修改過(guò)的信息不改變,刪除掉的數(shù)據(jù)還在顯示,你掐指一算,估計(jì)是數(shù)據(jù)庫(kù)主從不同步。與其他提供數(shù)據(jù)同步的數(shù)據(jù)庫(kù)一樣,MongoDB 也會(huì)遇到同步延遲的問(wèn)題,在MongoDB的Replica Sets模式中,同步延遲也經(jīng)常是困擾使用者的一個(gè)大問(wèn)題。
什么是同步延遲?
首先,要出現(xiàn)同步延遲,必然是在有數(shù)據(jù)同步的場(chǎng)合,在 MongoDB 中,有兩種數(shù)據(jù)冗余方式,一種是Master-Slave 模式,一種是Replica Sets模式。這兩個(gè)模式本質(zhì)上都是在一個(gè)節(jié)點(diǎn)上執(zhí)行寫(xiě)操作, 另外的節(jié)點(diǎn)將主節(jié)點(diǎn)上的寫(xiě)操作同步到自己這邊再進(jìn)行執(zhí)行。在MongoDB中,所有寫(xiě)操作都會(huì)產(chǎn)生 oplog,oplog 是每修改一條數(shù)據(jù)都會(huì)生成一條,如果你采用一個(gè)批量 update 命令更新了 N 多條數(shù)據(jù), 那么抱歉,oplog 會(huì)有很多條,而不是一條。所以同步延遲就是寫(xiě)操作在主節(jié)點(diǎn)上執(zhí)行完后,從節(jié)點(diǎn)還沒(méi)有把 oplog 拿過(guò)來(lái)再執(zhí)行一次。而這個(gè)寫(xiě)操作的量越大,主節(jié)點(diǎn)與從節(jié)點(diǎn)的差別也就越大,同步延遲也就越大了。
同步延遲帶來(lái)的問(wèn)題
首先,同步操作通常有兩個(gè)效果,一是讀寫(xiě)分離,將讀操作放到從節(jié)點(diǎn)上來(lái)執(zhí)行,從而減少主節(jié)點(diǎn)的 壓力。對(duì)于大多數(shù)場(chǎng)景來(lái)說(shuō),讀多寫(xiě)少是基本特性,所以這一點(diǎn)是很有用的。
另一個(gè)作用是數(shù)據(jù)備份, 同一個(gè)寫(xiě)操作除了在主節(jié)點(diǎn)執(zhí)行之外,在從節(jié)點(diǎn)上也同樣執(zhí)行,這樣我們就有多份同樣的數(shù)據(jù),一旦 主節(jié)點(diǎn)的數(shù)據(jù)因?yàn)楦鞣N天災(zāi)人禍無(wú)法恢復(fù)的時(shí)候,我們至少還有從節(jié)點(diǎn)可以依賴(lài)。但是主從延遲問(wèn)題 可能會(huì)對(duì)上面兩個(gè)效果都產(chǎn)生不好的影響。
如果主從延遲過(guò)大,主節(jié)點(diǎn)上會(huì)有很多數(shù)據(jù)更改沒(méi)有同步到從節(jié)點(diǎn)上。這時(shí)候如果主節(jié)點(diǎn)故障,就有兩種情況:
1)主節(jié)點(diǎn)故障并且無(wú)法恢復(fù),如果應(yīng)用上又無(wú)法忍受這部分?jǐn)?shù)據(jù)的丟失,我們就得想各種辦法將這部 數(shù)據(jù)更改找回來(lái),再寫(xiě)入到從節(jié)點(diǎn)中去。可以想象,即使是有可能,那這也絕對(duì)是一件非常惡心的活。
2)主節(jié)點(diǎn)能夠恢復(fù),但是需要花的時(shí)間比較長(zhǎng),這種情況如果應(yīng)用能忍受,我們可以直接讓從節(jié)點(diǎn)提 供服務(wù),只是對(duì)用戶(hù)來(lái)說(shuō),有一段時(shí)間的數(shù)據(jù)丟失了,而如果應(yīng)用不能接受數(shù)據(jù)的不一致,那么就只能下線整個(gè)業(yè)務(wù),等主節(jié)點(diǎn)恢復(fù)后再提供服務(wù)了。
如果你只有一個(gè)從節(jié)點(diǎn),當(dāng)主從延遲過(guò)大時(shí),由于主節(jié)點(diǎn)只保存最近的一部分 oplog,可能會(huì)導(dǎo)致從節(jié)點(diǎn)不得不進(jìn)行 resync 操作,全量從主節(jié)點(diǎn)同步數(shù)據(jù)。
帶來(lái)的問(wèn)題是:當(dāng)從節(jié)點(diǎn)全量同步的時(shí)候,實(shí)際只有主節(jié)點(diǎn)保存了完整的數(shù)據(jù),這時(shí)候如果主節(jié)點(diǎn)故障,很可能全部數(shù)據(jù)都丟掉了。
更多內(nèi)容參考:https://www.cnblogs.com/nulige/p/7613721.html