MongoDB的集群模式有三種:
- 主從(Master-Slaver),MongoDB 3.6徹底廢棄
- 副本集(Replica Set)
- 分片(Sharding)
本章主要講述副本集(Replica Set)佑菩。
一盾沫、副本集介紹
1.1 什么是副本集
MongoDB 副本集是將數(shù)據(jù)同步在多個服務(wù)器的過程裁赠,復(fù)制提供了數(shù)據(jù)的冗余備份,并在多個服務(wù)器上存儲數(shù)據(jù)副本赴精,提高了數(shù)據(jù)的可用性佩捞, 并可以保證數(shù)據(jù)的安全性,同時還允許從硬件故障和服務(wù)中斷中恢復(fù)數(shù)據(jù)蕾哟。
1.2 什么是 Oplog
Oplog
是MongoDB Primary(主節(jié)點)和Secondary(從節(jié)點)在副本集建立期間和建立完成之后的復(fù)制介質(zhì)一忱。Primary中所有的寫入操作都會記錄到Oplog
中,然后從節(jié)點會來主節(jié)點拉取Oplog
并應(yīng)用到自己的節(jié)點上谭确。這里的Oplog
是MongoDB local數(shù)據(jù)庫的一個集合帘营,它是Capped collection,通俗意思就是它是固定大小逐哈,循環(huán)使用的仪吧。如下圖:
Oplog
中的內(nèi)容如下:
{
"ts" : Timestamp(1446011584, 2),
"h" : NumberLong("1687359108795812092"),
"v" : 2,
"op" : "i",
"ns" : "test.nosql",
"o" : { "_id" : ObjectId("563062c0b085733f34ab4129"), "name" : "mongodb", "score" : "100" }
}
- ts: 操作時間,當(dāng)前timestamp + 計數(shù)器鞠眉,計數(shù)器每秒都被重置
- h:操作的全局唯一標(biāo)識
- v:oplog版本信息
- op:操作類型
- i:插入操作
- u:更新操作
- d:刪除操作
- c:執(zhí)行命令(如createDatabase薯鼠,dropDatabase)
- n:空操作,特殊用途
- ns:操作針對的集合
- o:操作內(nèi)容械蹋,如果是更新操作
- o2:操作查詢條件出皇,僅update操作包含該字段
1.2 副本集的結(jié)構(gòu)與原理
如上圖所示,副本集由一組mongo實例組成哗戈,提供了數(shù)據(jù)冗余與高可用性郊艘。相對于主從模式,該模式可以在主節(jié)點掛掉的時候通過選舉算法自動選舉出新的主節(jié)點唯咬,保證服務(wù)的可用性纱注。
該模式由三個角色組成:
- primary: 主節(jié)點,是唯一能夠接收寫請求的節(jié)點胆胰。一旦主節(jié)點不可用狞贱,會選出新的主節(jié)點
- secondaries: 從節(jié)點,提供數(shù)據(jù)備份和讀功能蜀涨,并且能在主節(jié)點掛掉的時候被選舉為新的主節(jié)點瞎嬉。
- arbiter: 投票節(jié)點或者叫仲裁節(jié)點。該角色是可選的厚柳,所以圖上也沒有畫出來氧枣。投票節(jié)點其本身并不包含數(shù)據(jù)集,也無法被升級為主節(jié)點别垮,但是便监,一旦當(dāng)前的主節(jié)點不可用時,投票節(jié)點就會參與到新的主節(jié)點選舉的投票中碳想。投票節(jié)點僅在副本集成員為偶數(shù)個的時候需要烧董,如果在擁有奇數(shù)個復(fù)制集成員的復(fù)制集中新增了一個投票節(jié)點毁靶,復(fù)制集可能會遇到選舉僵局。
主節(jié)點上能夠完成讀寫操作,從節(jié)點僅能用于讀操作解藻。主節(jié)點需要記錄所有改變數(shù)據(jù)庫狀態(tài)的操作,這些記錄保存在oplog
中,各個從節(jié)點通過此oplog
來復(fù)制數(shù)據(jù)并應(yīng)用于本地,保持本地的數(shù)據(jù)與主節(jié)點的一致老充。oplog
具有冪等性,即無論執(zhí)行幾次其結(jié)果一致葡盗。
集群中的各節(jié)點還會通過傳遞心跳信息來檢測各自的健康狀況螟左。當(dāng)主節(jié)點故障時,多個從節(jié)點會觸發(fā)一次新的選舉操作,并選舉其中的一個成為新的主節(jié)點(通常誰的優(yōu)先級更高,誰就是新的主節(jié)點),心跳信息默認(rèn)每 2 秒傳遞一次。
客戶端連接到副本集后觅够,不關(guān)心具體哪一臺機器是否掛掉胶背。主服務(wù)器負(fù)責(zé)整個副本集的讀寫,副本集定期同步數(shù)據(jù)備份喘先。一旦主節(jié)點掛掉钳吟,副本節(jié)點就會選舉一個新的主服務(wù)器。這一切對于應(yīng)用服務(wù)器不需要關(guān)心窘拯。
副本集中的副本節(jié)點在主節(jié)點掛掉后通過心跳機制檢測到后红且,就會在集群內(nèi)發(fā)起主節(jié)點的選舉機制,自動選舉出一位新的主服務(wù)器涤姊。
MongoDB官方建議副本集至少需要三個節(jié)點暇番。3.0之前最多12個節(jié)點,3.0開始節(jié)點數(shù)量能夠達到50個思喊。限制副本節(jié)點的數(shù)量,主要是因為一個集群中過多的副本節(jié)點,增加了復(fù)制的成本,反而拖累了集群的整體性能壁酬。太多的副本節(jié)點參與選舉,也會增加選舉的時間。而官方建議奇數(shù)的節(jié)點,是為了避免選舉僵局的發(fā)生(平局)恨课。
1.3 副本集數(shù)據(jù)同步
Primary節(jié)點寫入數(shù)據(jù)舆乔,Secondary通過讀取Primary的oplog得到復(fù)制信息,開始復(fù)制數(shù)據(jù)并且將復(fù)制信息寫入到自己的oplog剂公。如果某個操作失敗希俩,則備份節(jié)點停止從當(dāng)前數(shù)據(jù)源復(fù)制數(shù)據(jù)。如果某個備份節(jié)點由于某些原因掛掉了纲辽,當(dāng)重新啟動后斜纪,就會自動從oplog的最后一個操作開始同步,同步完成后文兑,將信息寫入自己的oplog盒刚,由于復(fù)制操作是先復(fù)制數(shù)據(jù),復(fù)制完成后再寫入oplog绿贞,有可能相同的操作會同步兩份因块,不過MongoDB在設(shè)計之初就考慮到這個問題,將oplog的同一個操作
執(zhí)行多次籍铁,與執(zhí)行一次的效果是一樣的涡上。簡單的說就是:
當(dāng)Primary節(jié)點完成數(shù)據(jù)操作后趾断,Secondary會做出一系列的動作保證數(shù)據(jù)的同步:
- 檢查自己local庫的oplog.rs集合找出最近的時間戳。
- 檢查Primary節(jié)點local庫oplog.rs集合吩愧,找出大于此時間戳的記錄芋酌。
- 將找到的記錄插入到自己的oplog.rs集合中,并執(zhí)行這些操作雁佳。
副本集的同步和主從同步一樣脐帝,都是異步同步的過程,不同的是副本集有個自動故障轉(zhuǎn)移的功能糖权。其原理是:Secondary端從primary端獲取日志堵腹,然后在自己身上完全順序的執(zhí)行日志所記錄的各種操作(該日志是不記錄查詢操作的),這個日志就是local數(shù)據(jù) 庫中的oplog.rs表星澳,默認(rèn)在64位機器上這個表是比較大的疚顷,占磁盤大小的5%,oplog.rs的大小可以在啟動參數(shù)中設(shè)定:--oplogSize 1000,單位是M禁偎。
1.4 何時觸發(fā)選舉
MongoDB 在下面幾個條件觸發(fā)之下進行選舉:
- 初始化副本集時腿堤;
- 備份節(jié)點無法和主節(jié)點通訊時(可能主節(jié)點宕或網(wǎng)絡(luò)原因);
- Primary 手動降級如暖,rs.stepDown(sec)笆檀,默認(rèn) 60s。
選舉的步驟如下:
- 得到每個服務(wù)器節(jié)點的最后操作時間戳装处。每個 mongodb 都有 oplog 機制會記錄本機的操作误债,方便和主服務(wù)器進行對比數(shù)據(jù)是否同步還可以用于錯誤恢復(fù);
- 如果集群中大部分服務(wù)器宕機了妄迁,保留活著的節(jié)點都為 secondary 狀態(tài)并停止選舉寝蹈;
- 如果集群中選舉出來的主節(jié)點或者所有從節(jié)點最后一次同步時間看起來很舊了,停止選舉等待人工操作登淘;
- 如果上面都沒有問題就選擇最后操作時間戳最新(保證數(shù)據(jù)最新)的服務(wù)器節(jié)點作為主節(jié)點箫老。
二、示例
副本集的啟動黔州,和從節(jié)點加入到副本集的操作耍鬓,只能在主節(jié)點上完成,但是主節(jié)點隨時可以轉(zhuǎn)移到其他從節(jié)點流妻。
啟動一個副本集系統(tǒng)的基本步驟如下:
- 在主節(jié)點啟動 mongod 服務(wù)時牲蜀,可以使用 --replSet 啟動副本集,同時指定副本集名稱绅这;
- 連接主節(jié)點涣达,初始化新的副本集;
- 啟動各個從節(jié)點 mongod 服務(wù),同時這些從節(jié)點也必須初始化副本集度苔,使用同一個副本集 id匆篓;
- 在主節(jié)點將這些從節(jié)點加入主節(jié)點副本集;
下面演示 3 個 mongodb 創(chuàng)建一個副本集系統(tǒng):
1)主節(jié)點啟動 mongod 服務(wù)
$ mongod --port 27017 --dbpath "/usr/local/mongodb/data" --replSet simon
simon 為 副本集ID
2) 2 個從節(jié)點分別啟動 mongod 服務(wù)
$ mongod --port 27017 --dbpath "/usr/local/mongodb/data" --replSet simon
3)連接到主節(jié)點 mongodb寇窑,進行副本集的初始化和配置
$ mongo
> rs.initiate() # 初始化的副本集
> rs.add("192.168.10.58:27107") # 加入從節(jié)點鸦概,該節(jié)點為 192.168.10.58 主機 27107 端口上的 mongod 服務(wù)
> rs.add("192.168.10.138:27107") # 加入從節(jié)點,該節(jié)點為 192.168.10.138 主機 27107 端口上的 mongod 服務(wù)
也可以這樣設(shè)置
$ mongo
>rs.initiate({"_id":"simon","members":[
{
"_id":1,
"host":"192.168.10.58:27017",
"priority":1
},
{
"_id":2,
"host":"192.168.10.138:27017",
"priority":1
}
]
}
)
-
_id
: 副本集的名稱 -
members
: 副本集的服務(wù)器列表 -
_id
: 服務(wù)器的唯一ID -
host
: 服務(wù)器主機 -
priority
: 是優(yōu)先級甩骏,默認(rèn)為1窗市,優(yōu)先級0為被動節(jié)點,不能成為活躍節(jié)點横漏。優(yōu)先級不位0則按照有大到小選出活躍節(jié)點 -
arbiterOnly
: 仲裁節(jié)點谨设,只參與投票熟掂,不接收數(shù)據(jù)缎浇,也不能成為活躍節(jié)點。
此時一個副本系統(tǒng)已經(jīng)完成赴肚,所有操作直接面向主節(jié)點素跺,實際操作由整個副本集集群提供,默認(rèn)是從主節(jié)點讀取
查看副本集信息
> rs.conf() # 查看副本集的配置
> rs.status() # 查看副本集狀態(tài)
> rs.isMaster() # 查看該主機節(jié)點是否為副本集主節(jié)點
設(shè)置從節(jié)點讀寫策略
> rs.getMongo().setReadPref(STRATEGY)
具體策略如下:
- Primary 從主節(jié)點讀扔指厌;
- secondary 從從節(jié)點讀取踊跟;
- nearest 從網(wǎng)絡(luò)延遲最小的節(jié)點讀炔妊椤;
- primaryPreferred 基本上從主節(jié)點讀取商玫,主節(jié)點不可用時箕憾,從從節(jié)點的讀取拳昌;
- secondaryPreferred 基本上從從節(jié)點讀取袭异,從節(jié)點不可用時,從主節(jié)點讀染嫣佟御铃;