mongodb副本集高可用架構


一、簡介

Mongodb復制集由一組Mongod實例(進程)組成,包含一個Primary節點和多個Secondary節點。
Mongodb Driver(客戶端)的所有數據都寫入Primary,Secondary從Primary同步寫入的數據,以保持復制集內所有成員存儲相同的數據集,實現數據的高可用。

使用場景

  • 數據冗余,用做故障恢復使用,當發生硬件故障或者其它原因造成的宕機時,可以使用副本進行恢復。
  • 讀寫分離,讀的請求分流到副本上,減輕主節點的讀壓力。

一個典型的副本集架構如下圖所示:

二、副本集角色

  1. 主節點(Primary)
    接收所有的寫請求,然后把修改同步到所有Secondary。一個Replica Set只能有一個Primary節點,當Primary掛掉后,其他Secondary或者Arbiter節點會重新選舉出來一個主節點。
    默認讀請求也是發到Primary節點處理的,可以通過修改客戶端連接配置以支持讀取Secondary節點。

  2. 副本節點(Secondary)
    與主節點保持同樣的數據集。當主節點掛掉的時候,參與選主。

  3. 仲裁者(Arbiter)
    不保有數據,不參與選主,只進行選主投票。使用Arbiter可以減輕數據存儲的硬件需求,Arbiter幾乎沒什么大的硬件資源需求,但重要的一點是,在生產環境下它和其他數據節點不要部署在同一台機器上。

三、兩種架構模式

  1. PSS
    Primary + Secondary + Secondary模式,通過Primary和Secondary搭建的Replica Set
    Diagram of a 3 member replica set that consists of a primary and two secondaries.

該模式下 Replica Set節點數必須為奇數,目的是選主投票的時候要出現大多數才能進行選主決策。

  1. PSA
    Primary + Secondary + Arbiter模式,使用Arbiter搭建Replica Set

偶數個數據節點,加一個Arbiter構成的Replica Set

四、選舉機制

復制集通過 replSetInitiate 命令或 rs.initiate() 命令進行初始化。
初始化后各個成員間開始發送心跳消息,並發起 Primary 選舉操作,獲得大多數成員投票支持的節點,會成為 Primary,其余節點成為 Secondary。

config = {
    _id : "my_replica_set",
    members : [
        {_id : 0, host : "rs1.example.net:27017"},
        {_id : 1, host : "rs2.example.net:27017"},
        {_id : 2, host : "rs3.example.net:27017"},
  ]
}
rs.initiate(config)

大多數
假設復制集內投票成員(后續介紹)數量為 N,則大多數為 N/2 + 1,當復制集內存活成員數量不足大多數時,整個復制集將無法選舉出 Primary,復制集將無法提供寫服務,處於只讀狀態。
關於大多數的計算如下表所示

投票成員數 大多數 容忍失效數
1 1 0
2 2 0
3 2 1
4 3 1
5 3 2

Mongodb副本集的選舉基於Bully算法,這是一種協調者競選算法,詳細解析可以參考這里
Primary 的選舉受節點間心跳、優先級、最新的 oplog 時間等多種因素影響。官方文檔對於選舉機制的說明

特殊角色

  • Arbiter
    Arbiter 節點只參與投票,不能被選為 Primary,並且不從 Primary 同步數據。
    當節點宕機導致復制集無法選出 Primary時,可以給復制集添加一個 Arbiter 節點,即使有節點宕機,仍能選出 Primary。
    Arbiter 本身不存儲數據,是非常輕量級的服務,當復制集成員為偶數時,最好加入一個 Arbiter 節點,以提升復制集可用性。

  • Priority0
    Priority0節點的選舉優先級為0,不會被選舉為 Primary。
    比如你跨機房 A、B 部署了一個復制集,並且想指定 Primary 必須在 A 機房,這時可以將 B 機房的復制集成員 Priority 設置為0,這樣 Primary 就一定會是 A 機房的成員。
    (注意:如果這樣部署,最好將大多數節點部署在 A 機房,否則網絡分區時可能無法選出 Primary。)

  • Vote0
    Mongodb 3.0里,復制集成員最多50個,參與 Primary 選舉投票的成員最多7個,其他成員(Vote0)的 vote 屬性必須設置為0,即不參與投票。

  • Hidden
    Hidden 節點不能被選為主(Priority 為0),並且對 Driver 不可見。
    因 Hidden 節點不會接受 Driver 的請求,可使用 Hidden 節點做一些數據備份、離線計算的任務,不會影響復制集的服務。

  • Delayed
    Delayed 節點必須是 Hidden 節點,並且其數據落后與 Primary 一段時間(可配置,比如1個小時)。
    因 Delayed 節點的數據比 Primary 落后一段時間,當錯誤或者無效的數據寫入 Primary 時,可通過 Delayed 節點的數據來恢復到之前的時間點。

觸發選舉條件

  • 初始化一個副本集時。
  • 從庫不能連接到主庫(默認超過10s,可通過heartbeatTimeoutSecs參數控制),由從庫發起選舉
  • 主庫放棄primary 角色,比如執行rs.stepdown 命令

Mongodb副本集通過心跳檢測實現自動failover機制,進而實現高可用

五、數據同步

Primary 與 Secondary 之間通過 oplog 來同步數據,Primary 上的寫操作完成后,會向特殊的 local.oplog.rs 特殊集合寫入一條 oplog,Secondary 不斷的從 Primary 取新的 oplog 並應用。
因 oplog 的數據會不斷增加,local.oplog.rs 被設置成為一個 capped 集合,當容量達到配置上限時,會將最舊的數據刪除掉。
另外考慮到 oplog 在 Secondary 上可能重復應用,oplog 必須具有冪等性,即重復應用也會得到相同的結果。
如下 oplog 的格式,包含 ts、h、op、ns、o 等字段。

{
"ts" : Timestamp(1446011584, 2),
"h" : NumberLong("1687359108795812092"),
"v" : 2,
"op" : "i",
"ns" : "test.nosql",
"o" : { "_id" : ObjectId("563062c0b085733f34ab4129"), "name" : "mongodb", "score" : "100" }
}
屬性 說明
ts 操作時間,當前 timestamp + 計數器,計數器每秒都被重置
h 操作的全局唯一標識
v oplog 版本信息
op 操作類型
op.i 插入操作
op.u 更新操作
op.d 刪除操作
op.c 執行命令(如 createDatabase,dropDatabase)
op.n 空操作,特殊用途
ns 操作針對的集合
o 操作內容
o2 操作查詢條件,僅 update 操作包含該字段。

Secondary 初次同步數據時,會先執行 init sync,從 Primary(或其他數據更新的 Secondary)同步全量數據,
然后不斷通過執行tailable cursor從 Primary 的 local.oplog.rs 集合里查詢最新的 oplog 並應用到自身。

異常回滾
當 Primary 宕機時,如果有數據未同步到 Secondary,當 Primary 重新加入時,如果新的 Primary 上已經發生了寫操作,則舊 Primary 需要回滾部分操作,以保證數據集與新的 Primary 一致。
舊 Primary 將回滾的數據寫到單獨的 rollback 目錄下,數據庫管理員可根據需要使用 mongorestore 進行恢復

六、讀寫配置

Read Preference
默認情況下,復制集的所有讀請求都發到 Primary,Driver 可通過設置 Read Preference 來將讀請求路由到其他的節點。

  • primary:默認規則,所有讀請求發到 Primary;
  • primaryPreferred:Primary 優先,如果 Primary 不可達,請求 Secondary;
  • secondary:所有的讀請求都發到 secondary;
  • secondaryPreferred:Secondary 優先,當所有 Secondary 不可達時,請求 Primary;
  • nearest:讀請求發送到最近的可達節點上(通過 ping 探測得出最近的節點)。
    關於read-preference

Write Concern
默認情況下,Primary 完成寫操作即返回,Driver 可通過設置 Write Concern (參見這里)來設置寫成功的規則。

如下的 write concern 規則設置寫必須在大多數節點上成功,超時時間為5s。

db.products.insert(
  { item: "envelopes", qty : 100, type: "Clasp" },
  { writeConcern: { w: majority, wtimeout: 5000 } }
)

關於write-concern

參考文檔

搭建高可用mongodb集群
http://www.lanceyan.com/tech/mongodb_repset2.html

深入淺出Mongodb復制
http://www.mongoing.com/archives/5200

mongodb副本集原理
https://yq.aliyun.com/articles/64?spm=0.0.0.0.9jrPm8

副本集主備切換
https://docs.mongodb.com/manual/tutorial/force-member-to-be-primary/index.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM