MongoDB副本集

MongoDB有主從復制和副本集兩種復制模式,主從復制最大的問題就是無法自動故障轉移,MongoDB副本集則解決了主從模式無法自動故障轉義的缺點。

MongoDB副本集是將數據同步在多個服務器的過程。復制提供了數據的冗余備份,并在多個服務器上存儲數據副本,提高了數據的可用性, 并可以保證數據的安全性,用于災難恢復,無需停機維護,分布式讀取數據。

特征

  • N 個節(jié)點的集群
  • 任何節(jié)點可作為主節(jié)點
  • 所有寫入操作都在主節(jié)點上
  • 自動故障轉移(如果主節(jié)點10s以上與其他節(jié)點失去通信,其他節(jié)點將會選舉新的節(jié)點作為主節(jié)點)
  • 自動恢復
    MongoDB的副本集在主機宕機后,副本會接管主節(jié)點成為主節(jié)點,不會出現(xiàn)宕機的情況。
  • 副本節(jié)點同步主節(jié)點操作是異步的,會導致副本集無法返回最新的數據給客戶端程序。

副本集復制原理

mongodb的復制至少需要兩個節(jié)點。其中一個是主節(jié)點,負責處理客戶端請求,其余的都是從節(jié)點,負責復制主節(jié)點上的數據。

主節(jié)點記錄在其上的所有操作oplog,從節(jié)點定期輪詢主節(jié)點獲取這些操作,然后對自己的數據副本執(zhí)行這些操作,從而保證從節(jié)點的數據與主節(jié)點一致。
oplog 具有冪等性,即無論執(zhí)行幾次其結果一致,這個比 mysql 的二進制日志更好用


  • 副本集使用的是 n 個 mongod 節(jié)點,構建具備自動的容錯功能(auto-failover),自動恢復的(auto-recovery)的高可用方案。
  • 對于副本集中的Secondary節(jié)點默認是不可讀的。
  • 可以使用副本集來實現(xiàn)讀寫分離。通過在連接時指定或者在主庫指定 slave,由Secondary 來分擔讀的壓力,Primary只承擔寫操作。
  • 主實例接受客戶的寫操作,副本集只能有一個主實例,因為為了維持數據一致性,只有一個實例可寫,主實例的日志保存在oplog。

集群中的各節(jié)點還會通過傳遞心跳信息來檢測各自的健康狀況。當主節(jié)點故障時,多個從節(jié)點會觸發(fā)一次 新的選舉操作,并選舉其中的一個成為新的主節(jié)點(通常誰的優(yōu)先級更高,誰就是新的主節(jié)點),心跳信息默認每 2 秒傳遞一次


心跳檢測:
整個集群需要保持一定的通信才能知道哪些節(jié)點活著哪些節(jié)點掛掉。mongodb節(jié)點會向副本集中的其他節(jié)點每兩秒就會發(fā)送一次pings包,如果其他節(jié)點在10秒鐘
之內沒有返回就標識為不能訪問。每個節(jié)點內部都會維護一個狀態(tài)映射表,表明當前每個節(jié)點是什么角色、日志時間戳等關鍵信息。如果是主節(jié)點,除了維護映射表外還需要檢查自己能否和集群中內大部分節(jié)點通訊,如果不能則把自己降級為secondary只讀節(jié)點。

副本集包括三種節(jié)點:主節(jié)點、從節(jié)點、仲裁節(jié)點。
1)主節(jié)點負責處理客戶端請求,讀、寫數據, 記錄在其上所有操作的 oplog;
2)從節(jié)點定期輪詢主節(jié)點獲取這些操作,然后對自己的數據副本執(zhí)行這些操作,從而保證從節(jié)點的數據與主節(jié)點一致。默認情況下,從節(jié)點不支持外部讀取,但可以設置;
副本集的機制在于主節(jié)點出現(xiàn)故障的時候,余下的節(jié)點會選舉出一個新的主節(jié)點,從而保證系統(tǒng)可以正常運行。
3)仲裁節(jié)點不復制數據,僅參與投票。由于它沒有訪問的壓力,比較空閑,因此不容易出故障。由于副本集出現(xiàn)故障的時候,存活的節(jié)點必須大于副本集節(jié)點總數的一半,否則無法選舉主節(jié)點,或者主節(jié)點會自動降級為從節(jié)點,整個副本集變?yōu)橹蛔x。因此,增加一個不容易出故障的仲裁節(jié)點,可以增加有效選票,降低整個副本集不可用的風險。仲裁節(jié)點可多于一個。也就是說只參與投票,不接收復制的數據,也不能成為活躍節(jié)點。

官方推薦MongoDB副本節(jié)點最少為3臺, 建議副本集成員為奇數,最多12個副本節(jié)點,最多7個節(jié)點參與選舉。
限制副本節(jié)點的數量,主要是因為一個集群中過多的副本節(jié)點,增加了復制的成本,反而拖累了集群的整體性能。 太多的副本節(jié)點參與選舉,也會增加選舉的時間。而官方建議奇數的節(jié)點,是為了避免腦裂的發(fā)生。

副本集工作流程

備份節(jié)點的工作原理過程可以大致描述為,備份節(jié)點定期輪詢主節(jié)點上的數據操作,然后對自己的數據副本進行這些操作,從而保證跟主節(jié)點的數據同步。至于主節(jié)點上的所有數據庫狀態(tài)改變 的操作,都會存放在一張?zhí)囟ǖ南到y(tǒng)表中。備份節(jié)點則是根據這些數據進行自己的數據更新。

oplog
上面提到的數據庫狀態(tài)改變的操作,稱為 oplog(operation log,主節(jié)點操作記錄)。oplog 存儲在 local 數據庫的"oplog.rs"表中。副本集中備份節(jié)點異步的從主節(jié)點同步 oplog,然后重新 執(zhí)行它記錄的操作,以此達到了數據同步的作用。
關于 oplog 有幾個注意的地方:
1)oplog 只記錄改變數據庫狀態(tài)的操作
2)存儲在 oplog 中的操作并不是和主節(jié)點執(zhí)行的操作完全一樣,例如"$inc"操作就會轉化為"$set"操作
3)oplog 存儲在固定集合中(capped collection),當 oplog 的數量超過 oplogSize,新的操作就會覆蓋就的操作

數據同步
在副本集中,有兩種數據同步方式:
1)initial sync(初始化):這個過程發(fā)生在當副本集中創(chuàng)建一個新的數據庫或其中某個節(jié)點剛從宕機中恢復,或者向副本集中添加新的成員的時候,
當secondary落后的數據量超過了oplog的大小,這樣也會被全量復制。默認的,副本集中的節(jié)點會從離它最近的節(jié)點復制 oplog 來同步數據,這個最近的節(jié)點可以是 primary 也可以是擁有最新 oplog 副本的 secondary 節(jié)點。該操作一般會重新初始化備份節(jié)點,開銷較大。
2)replication(復制):在初始化后這個操作會一直持續(xù)的進行著,以保持各個 secondary 節(jié)點之間的數據同步。

initial sync
當遇到無法同步的問題時,只能使用以下兩種方式進行 initial sync 了
1)第一種方式就是停止該節(jié)點,然后刪除目錄中的文件,重新啟動該節(jié)點。這樣,這個節(jié) 點就會執(zhí)行 initial sync
注意:通過這種方式,sync 的時間是根據數據量大小的,如果數據量過大,sync 時間就會很長,同時會有很多網絡傳輸,可能會影響其他節(jié)點的工作
2)第二種方式,停止該節(jié)點,然后刪除目錄中的文件,找一個比較新的節(jié)點,然后把該節(jié)點目 錄中的文件拷貝到要 sync 的節(jié)點目錄中。
通過上面兩種方式中的一種,都可以重新恢復該節(jié)點。不在進行截圖了。

副本集管理
1)查看oplog的信息 通過"db.printReplicationInfo()"命令可以查看 oplog 的信息
字段說明:
configured oplog size: oplog 文件大小
log length start to end: oplog 日志的啟用時間段
oplog first event time: 第一個事務日志的產生時間
oplog last event time: 最后一個事務日志的產生時間
now: 現(xiàn)在的時間
2)查看 slave 狀態(tài) 通過"db.printSlaveReplicationInfo()"可以查看 slave 的同步狀態(tài)
當插入一條新的數據,然后重新檢查 slave 狀態(tài)時,就會發(fā)現(xiàn) sync 時間更新了

副本集選舉過程

Mongodb副本集選舉采用的是Bully算法,這是一種協(xié)調者(主節(jié)點)競選算法,主要思想是集群的每個成員都可以聲明它是主節(jié)點并通知其他節(jié)點。別的節(jié)點可以選擇接受這個聲稱或是拒絕并進入主節(jié)點競爭,被其他所有節(jié)點接受的節(jié)點才能成為主節(jié)點。
節(jié)點按照一些屬性來判斷誰應該勝出,這個屬性可以是一個靜態(tài) ID,也可以是更新的度量像最近一次事務ID(最新的節(jié)點會勝出)

副本集的選舉過程大致如下:
1)得到每個服務器節(jié)點的最后操作時間戳。每個 mongodb 都有 oplog 機制會記錄本機的操作,方便和主服 務器進行對比數據是否同步還可以用于錯誤恢復。
2)如果集群中大部分服務器 down 機了,保留活著的節(jié)點都為 secondary 狀態(tài)并停止,不選舉了。
3)如果集群中選舉出來的主節(jié)點或者所有從節(jié)點最后一次同步時間看起來很舊了,停止選舉等待人來操作。
4)如果上面都沒有問題就選擇最后操作時間戳最新(保證數據是最新的)的服務器節(jié)點作為主節(jié)點。

副本集選舉的特點:
選舉還有個前提條件,參與選舉的節(jié)點數量必須大于副本集總節(jié)點數量的一半(建議副本集成員為奇數。最多12個副本節(jié)點,最多7個節(jié)點參與選舉)
如果已經小于一半了所有節(jié)點保持只讀狀態(tài)。集合中的成員一定要有大部分成員(即超過一半數量)是保持正常在線狀態(tài),3個成員的副本集,需要至少2個從屬節(jié)點是正常狀態(tài)。
如果一個從屬節(jié)點掛掉,那么當主節(jié)點down掉 產生故障切換時,由于副本集中只有一個節(jié)點是正常的,少于一半,則選舉失敗。
4個成員的副本集,則需要3個成員是正常狀態(tài)(先關閉一個從屬節(jié)點,然后再關閉主節(jié)點,產生故障切換,此時副本集中只有2個節(jié)點正常,則無法成功選舉出新主節(jié)點)。

副本集數據同步過程

Primary節(jié)點寫入數據,Secondary通過讀取Primary的oplog得到復制信息,開始復制數據并且將復制信息寫入到自己的oplog。如果某個操作失敗,則備份節(jié)點
停止從當前數據源復制數據。如果某個備份節(jié)點由于某些原因掛掉了,當重新啟動后,就會自動從oplog的最后一個操作開始同步,同步完成后,將信息寫入自己的oplog,由于復制操作是先復制數據,復制完成后再寫入oplog,有可能相同的操作會同步兩份,不過MongoDB在設計之初就考慮到這個問題,將oplog的同一個操作執(zhí)行多次,與執(zhí)行一次的效果是一樣的。簡單的說就是:

當Primary節(jié)點完成數據操作后,Secondary會做出一系列的動作保證數據的同步:
1)檢查自己local庫的oplog.rs集合找出最近的時間戳。
2)檢查Primary節(jié)點local庫oplog.rs集合,找出大于此時間戳的記錄。
3)將找到的記錄插入到自己的oplog.rs集合中,并執(zhí)行這些操作。

副本集的同步和主從同步一樣,都是異步同步的過程,不同的是副本集有個自動故障轉移的功能。其原理是:slave端從primary端獲取日志,然后在自己身上完全順序的執(zhí)行日志所記錄的各種操作(該日志是不記錄查詢操作的),這個日志就是local數據 庫中的oplog.rs表,默認在64位機器上這個表是比較大的,占磁盤大小的5%,
oplog.rs的大小可以在啟動參數中設 定:--oplogSize 1000,單位是M。

注意:在副本集的環(huán)境中,要是所有的Secondary都宕機了,只剩下Primary。最后Primary會變成Secondary,不能提供服務。

數據同步延遲問題

當你的用戶抱怨修改過的信息不改變,刪除掉的數據還在顯示,你掐指一算,估計是數據庫主從不同步。與其他提供數據同步的數據庫一樣,MongoDB 也會遇到同步延遲的問題,在MongoDB的Replica Sets模式中,同步延遲也經常是困擾使用者的一個大問題。

什么是同步延遲?
首先,要出現(xiàn)同步延遲,必然是在有數據同步的場合,在 MongoDB 中,有兩種數據冗余方式,一種是Master-Slave 模式,一種是Replica Sets模式。這兩個模式本質上都是在一個節(jié)點上執(zhí)行寫操作, 另外的節(jié)點將主節(jié)點上的寫操作同步到自己這邊再進行執(zhí)行。在MongoDB中,所有寫操作都會產生 oplog,oplog 是每修改一條數據都會生成一條,如果你采用一個批量 update 命令更新了 N 多條數據, 那么抱歉,oplog 會有很多條,而不是一條。所以同步延遲就是寫操作在主節(jié)點上執(zhí)行完后,從節(jié)點還沒有把 oplog 拿過來再執(zhí)行一次。而這個寫操作的量越大,主節(jié)點與從節(jié)點的差別也就越大,同步延遲也就越大了。

同步延遲帶來的問題
首先,同步操作通常有兩個效果,一是讀寫分離,將讀操作放到從節(jié)點上來執(zhí)行,從而減少主節(jié)點的 壓力。對于大多數場景來說,讀多寫少是基本特性,所以這一點是很有用的。
另一個作用是數據備份, 同一個寫操作除了在主節(jié)點執(zhí)行之外,在從節(jié)點上也同樣執(zhí)行,這樣我們就有多份同樣的數據,一旦 主節(jié)點的數據因為各種天災人禍無法恢復的時候,我們至少還有從節(jié)點可以依賴。但是主從延遲問題 可能會對上面兩個效果都產生不好的影響。

如果主從延遲過大,主節(jié)點上會有很多數據更改沒有同步到從節(jié)點上。這時候如果主節(jié)點故障,就有兩種情況:
1)主節(jié)點故障并且無法恢復,如果應用上又無法忍受這部分數據的丟失,我們就得想各種辦法將這部 數據更改找回來,再寫入到從節(jié)點中去。可以想象,即使是有可能,那這也絕對是一件非常惡心的活。
2)主節(jié)點能夠恢復,但是需要花的時間比較長,這種情況如果應用能忍受,我們可以直接讓從節(jié)點提 供服務,只是對用戶來說,有一段時間的數據丟失了,而如果應用不能接受數據的不一致,那么就只能下線整個業(yè)務,等主節(jié)點恢復后再提供服務了。

如果你只有一個從節(jié)點,當主從延遲過大時,由于主節(jié)點只保存最近的一部分 oplog,可能會導致從節(jié)點不得不進行 resync 操作,全量從主節(jié)點同步數據。
帶來的問題是:當從節(jié)點全量同步的時候,實際只有主節(jié)點保存了完整的數據,這時候如果主節(jié)點故障,很可能全部數據都丟掉了。

更多內容參考:https://www.cnblogs.com/nulige/p/7613721.html

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容