一 MongoDB 複製(副本集)
1.1 複製概述
MongoDB複製是將數據同步在多個服務器的過程。
複製提供了數據的冗餘備份,並在多個服務器上存儲數據副本,提升了數據的可用性, 並能夠保證數據的安全性。
複製還容許從硬件故障和服務中斷中恢復數據。
1.2 複製意義
- 保障數據的安全性
- 數據高可用性 (24*7)
- 災難恢復
- 無需停機維護(如備份,重建索引,壓縮)
- 分佈式讀取數據
注意:副本集不是爲了提升讀性能存在的,在進行oplog的時候,讀操做是被阻塞的;
提升讀取性能應該使用分片和索引,它的存在更可能是做爲數據冗餘,備份;
尤爲當主庫原本就面臨着大量的寫入壓力,對於副本集的節點,也一樣會面臨寫的壓力。
1.3 MongoDB複製原理
mongodb的複製至少須要兩個節點。其中一個是主節點,負責處理客戶端請求,其他的都是從節點,負責複製主節點上的數據。
mongodb各個節點常見的搭配方式爲:一主一從、一主多從。
主節點記錄在其上的全部操做oplog,從節點按期輪詢主節點獲取這些操做,而後對本身的數據副本執行這些操做,從而保證從節點的數據與主節點一致。
MongoDB複製結構圖以下所示:
添加Heartbeat監控副本之間的心跳架構:
設置一個仲裁節點架構:
說明:客戶端從主節點讀取數據,在客戶端寫入數據到主節點時, 主節點與從節點進行數據交互保障數據的一致性。
1.4 MongoDB複製過程
Primary節點寫入數據,Secondary經過讀取Primary的oplog獲得複製信息,開始複製數據而且將複製信息寫入到本身的oplog。若是某個操做失敗,則備份節點中止從當前數據源複製數據。若是某個備份節點因爲某些緣由掛掉了,當從新啓動後,就會自動從oplog的最後一個操做開始同步。同步完成後,將信息寫入本身的oplog,因爲複製操做是先複製數據,複製完成後再寫入oplog,有可能相同的操做會同步兩份,不過MongoDB在設計之初就考慮到這個問題,將oplog的同一個操做執行屢次,與執行一次的效果是同樣的。
當Primary節點完成數據操做後,Secondary的數據同步過程以下:
-
檢查本身local庫的oplog.rs集合找出最近的時間戳。
- 檢查Primary節點local庫oplog.rs集合,找出大於此時間戳的記錄。
- 將找到的記錄插入到本身的oplog.rs集合中,並執行這些操做。
副本集的同步和主從同步同樣,都是異步同步的過程,不一樣的是副本集有個自動故障轉移的功能。其原理是:slave端從primary端獲取日誌,而後在本身身上徹底順序的執行日誌所記錄的各類操做(該日誌是不記錄查詢操做的),這個日誌就是local數據庫中的oplog.rs表,默認在64位機器上這個表是比較大的,佔磁盤大小的5%,oplog.rs的大小能夠在啓動參數中設 定:--oplogSize 1000,單位是M。
注意:在副本集的環境中,要是全部的Secondary都宕機了,只剩下Primary。最後Primary會變成Secondary,不能提供服務。
1.5 副本集
副本集特徵:
- N 個節點的集羣;
- 任何節點可做爲主節點;
- 全部寫入操做都在主節點上;
- 自動故障轉移;
- 自動恢復。
集羣中沒有特定的主庫,主庫是選舉產生,若是主庫down了,會再選舉出一臺主庫。
mongoDB也能夠配置成主從模式,但官方已經不建議使用主從模式了,替代方案是採用副本集的模式。
副本集有如下特色:
- 最小構成是:primary,secondary,arbiter,通常部署是:primary,2 secondary。
- 成員數應該爲奇數,若是爲偶數的狀況下添加arbiter,arbiter不保存數據,只投票。
- 最大50 members,可是隻能有 7 voting members,其餘是non-voting members。
注意:在副本集的環境中,若是全部的Secondary都宕機了,只剩下Primary。最後Primary會變成Secondary,且不能提供服務。
二 前期準備
-
NTP同步;
- 關閉SELinux;
- 關閉防火牆或放通相應規則;
- 全部節點安裝MongoDB,參考《002.MongoDB社區版安裝》;
節點規劃:
主機名
|
IP
|
類型
|
備註
|
mongodb01
|
172.24.8.71
|
primary
|
主節點
|
mongodb02
|
172.24.8.72
|
secondary
|
此節點
|
mongodb03
|
172.24.8.73
|
secondary
|
此節點
|
mongodb04
|
172.24.8.74
|
secondary
|
備節點(測試手動添加)
|
arbiter
|
172.24.8.75
|
arbiter
|
衝裁節點
|
追加解析:
1 [root@mongodb01 ~]# vi /etc/hosts
2 172.24.8.71 mongodb01
3 172.24.8.72 mongodb02
4 172.24.8.73 mongodb03
5 172.24.8.74 mongodb04
6 172.24.8.75 arbite
提示:全部節點均建議添加以上解析。
三 副本集正式部署
3.1 開啓遠程鏈接及副本集
1 [root@mongodb01 ~]# vi /etc/mongod.conf
2 ……
3 net:
4 port: 27017
5 bindIp: 172.24.8.71 #根據不一樣節點配置
6 ……
7 replication:
8 replSetName: my_rep #開啓副本集,全部節點必須一致
9 ……
10 [root@mongodb01 ~]# systemctl start mongod.service
11 [root@mongodb01 ~]# systemctl enable mongod.service
注意:在完成複製集初始化、新建用戶等操做以前必須保持security.authorization:enabled爲註釋狀態。
3.2 配置複製級成員
1 [root@mongodb01 ~]# mongo --host 172.24.8.71
2 > config = { _id: "my_rep", members: [
3 {_id: 0, host: "172.24.8.71:27017"},
4 {_id: 1, host: "172.24.8.72:27017"},
5 {_id: 2, host: "172.24.8.73:27017"}]
6 }
參數解釋:
"_id": 副本集的名稱
"members": 副本集的服務器列表
"_id": 服務器的惟一ID
"host": 服務器主機
"priority": 是優先級,默認爲1,優先級0爲被動節點,不能成爲活躍節點。優先級不爲0則按照有大到小選出活躍節點。
"arbiterOnly": 仲裁節點,只參與投票,不接收數據,也不能成爲活躍節點。
3.3 初始化副本集
1 > rs.initiate(config)
2 my_rep1:PRIMARY> rs.status() #查看集羣狀態
3.4 建立管理員用戶
1 [root@mongodb01 ~]# mongo --host 172.24.8.71
2 my_rep:PRIMARY> use admin #進入admin數據庫
3 my_rep:PRIMARY> db.createUser({ user: "admin", pwd: "admin", roles: [{ role: "userAdminAnyDatabase", db: "admin" }] })
4 my_rep:PRIMARY> db.auth("admin", "admin") #驗證建立結果
5 1
提示:以上爲建議項,建議建立一個管理員用於內部管理MongoDB。
mongodb中的用戶是基於身份role的,該管理員帳戶的 role是 userAdminAnyDatabase。 ‘userAdmin’表明用戶管理身份,’AnyDatabase’ 表明能夠管理任何數據庫。
db.auth()能夠驗證 用戶。
1 my_rep:PRIMARY> db.getUsers()
2 > db.system.users.find().pretty() #查看全局全部帳戶
提示:mongo shell 可經過.pretty() 對輸出進行JSON格式化,以便提升輸出的可讀性。
3.5 建立集羣用戶
1 [root@mongodb01 ~]# mongo --host 172.24.8.71 -u admin -p admin
2 my_rep1:PRIMARY> use admin
3 switched to db admin
4 my_rep1:PRIMARY> db.createUser({user:"clusteradmin",pwd:"clusteradmin",roles:[{role:"clusterAdmin",db:"admin"}]})
提示:3.2——3.5僅需在集羣任何一臺節點操做便可。
3.6 確認驗證
1 [root@mongodb01 ~]# mongo --host 172.24.8.72 -u clusteradmin -p clusteradmin
2 my_rep:SECONDARY> rs.status()
3 my_rep:SECONDARY> db.serverStatus().repl.primary #查看主節點
4 172.24.8.73:27017
四 集羣開啓權限
建議使用keyfile訪問控制的方式創建各個節點間的安全認證機制。
4.1 配置key
1 [root@mongodb01 ~]# mkdir -p /usr/local/keyfile
2 [root@mongodb01 ~]# openssl rand -base64 100 > /usr/local/keyfile/mongodb_keyfile
3 [root@mongodb01 ~]# chmod 600 /usr/local/keyfile/mongodb_keyfile
4 [root@mongodb01 ~]# chown -R mongod:mongod /usr/local/keyfile/
5 [root@mongodb01 ~]# scp -rp /usr/local/keyfile/ root@mongodb02:/usr/local/
6 [root@mongodb01 ~]# scp -rp /usr/local/keyfile/ root@mongodb03:/usr/local/
7 [root@mongodb01 ~]# scp -rp /usr/local/keyfile/ root@mongodb04:/usr/local/
8 [root@mongodb01 ~]# scp -rp /usr/local/keyfile/ root@arbiter:/usr/local/
9
10 [root@mongodb02 ~]# chown -R mongod:mongod /usr/local/keyfile/
11 [root@mongodb03 ~]# chown -R mongod:mongod /usr/local/keyfile/
12 [root@mongodb04 ~]# chown -R mongod:mongod /usr/local/keyfile/
13 [root@arbiter~]# chown -R mongod:mongod /usr/local/keyfile/
4.2 開啓權限
1 [root@mongodb01 ~]# vi /etc/mongod.conf
2 ……
3 security: #取消註釋
4 authorization: enabled #開啓驗證
5 keyFile: /usr/local/keyfile/mongodb_keyfile #key文件
6 ……
7 [root@mongodb01 ~]# systemctl restart mongod.service
提示:須要在全部節點進行開啓操做。
4.3 測試登錄
1 [root@mongodb01 ~]# mongo --host 172.24.8.71 -u clusteradmin -p clusteradmin
2 my_rep:PRIMARY> rs.status()
3 my_rep:PRIMARY> db.serverStatus().repl.primary #查看主節點
4 172.24.8.71:27017
五 成員管理
5.1 SECONDARY節點增長
1 [root@mongodb01 ~]# scp -rp /etc/mongod.conf root@mongodb04:/etc/mongod.conf
2 [root@mongodb04 ~]# vi /etc/mongod.conf #修改IP便可
3 net:
4 port: 27017
5 bindIp: 172.24.8.74
6 [root@mongodb04 ~]# systemctl restart mongod.service
7 [root@mongodb04 ~]# systemctl enable mongod.service
8 [root@mongodb01 ~]# mongo --host 172.24.8.71 -u clusteradmin -p clusteradmin
9 my_rep:PRIMARY> rs.add("172.24.8.74:27017")
5.2 節點刪除
1 my_rep:PRIMARY> rs.remove("172.24.8.74:27017")
提示:修改副本集成員配置時的限制:
- 不能修改_id;
- 不能將當前執行rs.reconfig命令的成員的優先級設置爲 0;
- 不能將仲裁者成員變爲非仲裁者成員,反正亦然;
- 不能將buildIndexes由false改成 true。
5.3 Secondary開放臨時讀
默認狀況下,Secondary是不提供服務的,即不能讀和寫。在特殊狀況下須要讀的可執行rs.slaveOk() ,只對當前鏈接有效。
5.4 節點提權
默認全部的節點priority都爲1,自動選舉primary,可經過如下方式手動在已運行的副本集中指定primary。
注意:如下方式更換主節點必須在當前primary節點操做。
1 my_rep:SECONDARY> db.serverStatus().repl.primary #查看主節點
2 172.24.8.72:27017
3 [root@mongodb02 ~]# mongo --host 172.24.8.72 -u clusteradmin -p clusteradmin
4 my_rep:PRIMARY> rs.status() #查看當前副本集狀態
1 my_rep:PRIMARY> rs.conf()
1 my_rep:PRIMARY> newcfg=rs.conf() #當前conf寫入變量
2 my_rep:PRIMARY> newcfg.members[0].priority=2 #修改conf中members序號0,即172.24.8.71優先級爲2
3 2
4 my_rep:PRIMARY> rs.reconfig(newcfg #從新載入conf
5 [root@mongodb01 ~]# mongo --host 172.24.8.71 -u clusteradmin -p clusteradmin
6 my_rep:PRIMARY> db.serverStatus().repl.primary #再次登陸查看primary節點
7 172.24.8.71:27017
5.5 ARBITER節點添加
1 [root@mongodb01 ~]# scp -rp /etc/mongod.conf root@arbiter:/etc/mongod.conf
2 [root@mongodb04 ~]# vi /etc/mongod.conf #修改IP便可
3 net:
4 port: 27017
5 bindIp: 172.24.8.75
6 [root@mongodb04 ~]# systemctl restart mongod.service
7 [root@mongodb04 ~]# systemctl enable mongod.service
8 [root@mongodb01 ~]# mongo --host 172.24.8.71 -u clusteradmin -p clusteradmin
9 my_rep:PRIMARY> rs.addArb("172.24.8.75:27017")
10 my_rep:PRIMARY> rs.status()
1 my_rep:PRIMARY> rs.conf()
提示:副本集要求參與選舉投票(vote)的節點數爲奇數,當咱們實際環境中由於機器等緣由限制只有兩個(或偶數)的節點,這時爲了實現 Automatic Failover引入另外一類節點:仲裁者(arbiter),仲裁者只參與投票不擁有實際的數據,而且不提供任何服務,所以它對物理資源要求不嚴格。
5.6 修改爲員狀態
1 my_rep:PRIMARY> rs.stepDown()
提示:rs.stepDown(60)表示讓主節點退化爲備份節點,並維持60秒。若是60s內沒有新的主節點被選舉出來,那麼當前節點能夠要求從新參與進行選舉。
5.7 鎖定主節點
將全部的備份節點的priority和votes都設置爲0,這樣只有主節點有投票權因此不管備份節點是否存在都不會致使主節點的狀態由primary變成other。
1 my_rep:PRIMARY> newconf=rs.config()
2 my_rep:PRIMARY> newconf.members[1].priority=0
3 my_rep:PRIMARY> newconf.members[1].votes=0
4 my_rep:PRIMARY> rs.reconfig(newconf)
5.8 阻止成員選舉
若是須要對主節點進行維護操做,可是不但願這段時間內其它成員選舉爲主節點,能夠在每一個備份節點上執行freeze命令,以強制它們始終處於備份節點的狀態。命令以秒爲單位。
1 my_rep:SECONDARY> rs.freeze(3600) #保持1個小時處於備份節點狀態。
2 my_rep:SECONDARY> rs.freeze(0) #再次在備份節點執行且將時間指定爲0就是「釋放」備份節點。
注意:若是在退位的備份節點上執行rs.freeze(0),可讓退位的備份節點從新變爲主節點。
六 副本集管理
6.1 查看複製狀況
1 my_rep:PRIMARY> db.printSlaveReplicationInfo()
2 source: 172.24.8.72:27017
3 syncedTo: Tue May 28 2019 19:43:40 GMT+0800 (CST)
4 0 secs (0 hrs) behind the primary
5 source: 172.24.8.73:27017
6 syncedTo: Tue May 28 2019 19:43:40 GMT+0800 (CST)
7 0 secs (0 hrs) behind the primary
解釋:
source:從庫的ip和端口。
syncedTo:目前的同步狀況,以及最後一次同步的時間。
在數據庫內容不變的狀況下是不一樣步的,數據庫變更就會立刻同步。
6.2 副本集複製鏈配置
MongoDB根據ping時間選擇同步源,一個成員向另外一個成員發送心跳請求,獲取心跳請求所耗費的時間(rs.status()中的"pingMs"記錄了成員到達相關成員的所花費的平均時間)。
MongosDB維護着不一樣成員間請求的平均花費時間。選擇同步源時,會選擇一個離本身比較近並且數據比本身新的成員。可是同一數據中心的成員可能會從同一數據中心的其餘成員處複製,而不是從位於另外一個數據中心的主節點處複製(這樣能夠減小網絡流量),因此會出現複製鏈的狀況,複製鏈越長會致使主節點的操做複製到全部的服務器所花費的時間越長,從而影響必定的性能。
1 [root@mongodb03 ~]# mongo --host 172.24.8.73 -u clusteradmin -p clusteradmin
2 my_rep:SECONDARY> db.adminCommand({"replSetGetStatus":1})['syncingTo']; #查看備份節點的複製源
3 172.24.8.71:27017
4 my_rep:SECONDARY> db.adminCommand({"replSetSyncFrom":"172.24.8.72:27017"}) #配置複製源
6.3 查看副本集狀態
1 my_rep:PRIMARY> rs.status()
6.4 查看副本集配置
1 my_rep:PRIMARY> rs.conf() #查看節點配置
6.5 強制從新配置副本集
若是副本集沒法選出新的主節點,這時須要從新配置副本集。能夠在備份節點上調用rs.reconfig(conf,{"force":ture})強制從新配置副本集。
備份節點收到新的配置文件以後,就會修改自身的配置,而且將新的配置發送給副本集中的其餘成員。副本集的其餘成員收到新的配置文件以後,會判斷配置文件的發送者是不是它們當前配置中的一個成員,若是是,纔會用新的配置文件對本身進行從新配置。
因此,若是新的配置修改了某些成員的主機名,則應該關閉被修改主機名的節點,並以單機模式啓動,手動修改locak.system.replset文檔,而後以副本集的方式從新啓動。
注意:conf必須是正確、有效的配置。並且強制從新配置只容許在備份節點執行。
6.6 查看副本集log狀態
1 my_rep:PRIMARY> rs.printReplicationInfo()
2 configured oplog size: 1194.595947265625MB
3 log length start to end: 14027secs (3.9hrs)
4 oplog first event time: Tue May 28 2019 17:21:54 GMT+0800 (CST)
5 oplog last event time: Tue May 28 2019 21:15:41 GMT+0800 (CST)
6 now: Tue May 28 2019 21:15:48 GMT+0800 (CST)
解釋:
configured oplog size:oplog配置的大小
log length start to end:oplog包含的操做時長。
oplog first event time:oplog第一條操做的時間。
oplog last event time:oplog最後一條操做的時間。
now:當前時間。
注意:oplog中第一條操做與最後一條操做的時間差就是操做日誌的長度。
6.7 查看複製延時
1 my_rep:PRIMARY> rs.printSlaveReplicationInfo()
2 source: 172.24.8.72:27017
3 syncedTo: Tue May 28 2019 21:17:40 GMT+0800 (CST)
4 0 secs (0 hrs) behind the primary
5 source: 172.24.8.73:27017
6 syncedTo: Tue May 28 2019 21:17:40 GMT+0800 (CST)
7 0 secs (0 hrs) behind the primary
8 source: 172.24.8.74:27017
9 syncedTo: Tue May 28 2019 21:17:40 GMT+0800 (CST)
10 0 secs (0 hrs) behind the primary
6.8 副本集信息查看(監控)命令彙總
1.複製集狀態查詢:rs.status()
2.查看當前副本集oplog狀態:rs.printReplicationInfo()
3.查看複製延遲:rs.printSlaveReplicationInfo()
4.查看服務狀態詳情:db.serverStatus()
5.查詢副本集配置:rs.conf()
6.主副本查詢:db.isMaster()
6.9 其餘常見維護命令
經過rs.help()命令,能夠查看副本集相關操做命令:
1 replSetHO:PRIMARY> rs.help()
2 rs.status() #查看副本集總體健康狀態
3 rs.initiate() #使用默認配置初始化副本集
4 rs.initiate(cfg) #使用指定配置,初始化副本集;這是咱們使用的命令
5 rs.conf() #從local.system.replset獲取副本集當前配置信息
6 rs.reconfig(cfg) #指定配置信息重置副本集;指定第二個參數{force:true},來強制更新
7 rs.add(hostportstr) #使用默認配置,給副本集添加新成員
8 rs.add(membercfgobj) #使用指定配置,給副本集添加新成員
9 rs.addArb(hostportstr) #給副本集添加一個仲裁節點,只投票,不會成爲數據節點
10 rs.stepDown([stepdownSecs, catchUpSecs]) #給PRIMARY降權,使之在指定時間內成爲SECONDARY,會恢復
11 rs.syncFrom(hostportstr) #使SECONDARY從指定的服務器同步數據
12 rs.freeze(secs) #讓本身在指定秒數內不會成爲PRIMARY
13 rs.remove(hostportstr) #從副本集刪除指定節點
14 rs.slaveOk() #SECONDARY節點默認是不能查詢的,須要執行該命令,使之能夠查詢
15 rs.printReplicationInfo() #查看操做日誌以及日誌時間
16 rs.printSlaveReplicationInfo() #查看全部SECONDARY延遲狀況
17 db.isMaster() #查詢當前PRIMARY信息
提示:更多副本集選舉參考官方:https://docs.mongodb.com/manual/core/replica-set-elections/。
七 副本集複製功能測試
7.1 受權
1 [root@mongodb01 ~]# mongo --host 172.24.8.71 -u admin -p admin
2 my_rep:PRIMARY> use admin
3 my_rep:PRIMARY> db.grantRolesToUser( "admin",[{ role: "dbOwner",db:"mydb" }])
7.2 插入數據
1 my_rep:PRIMARY> use mydb
2 my_rep:PRIMARY> db.age01.insert({name: 'zhangsan',
3 age: '18',
4 tel: '123456781',
5 love: ['apple','banana']
6 }
7.3 查看同步
1 [root@mongodb02 ~]# mongo --host 172.24.8.72 -u admin -p admin
2 my_rep:SECONDARY> rs.slaveOk()
3 my_rep:SECONDARY> use mydb
4 my_rep:SECONDARY> db.age01.count()
5 1
八 副本集故障轉移功能測試
8.1 關閉主節點
1 [root@mongodb01 ~]# mongo --host 172.24.8.71 -u clusteradmin -p clusteradmin
2 my_rep:PRIMARY> rs.status()
3 my_rep:PRIMARY> use admin
4 switched to db admin
5 my_rep:PRIMARY> db.shutdownServer()
6 [root@mongodb02 ~]# mongo --host 172.24.8.72 -u clusteradmin -p clusteradmin #登陸任意非關閉節點
7 my_rep:PRIMARY> rs.status()
8 my_rep:PRIMARY> db.serverStatus().repl.primary #查看主節點
9 172.24.8.72:27017
8.2 插入數據
1 [root@mongodb02 ~]# mongo --host 172.24.8.72 -u admin -p admin
2 my_rep:PRIMARY> use mydb
3 db.age01.insertOne({name: 'wanger', age: '15', tel: '123456783', love: ['pear','orange']})
8.3 開啓關閉節點
1 [root@mongodb01 ~]# systemctl restart mongod.service
2 [root@mongodb01 ~]# mongo --host 172.24.8.71 -u admin -p admin
3 my_rep:SECONDARY> use mydb
4 switched to db mydb
5 my_rep:SECONDARY> rs.slaveOk()
6 my_rep:SECONDARY> db.age01.find().pretty()
提示:當關閉節點mongo服務重啓啓動後,能正常以SECONDARY加入副本集,而且自動同步相關數據。
注意:全部的Secondary都宕機、或則副本集中只剩下一個節點,則該節點只能爲Secondary節點,也就意味着整個集羣只能進行讀操做而不能進行寫操做,當其餘節點恢復時,以前的primary節點仍然是primary節點。
當某個節點宕機後從新啓動該節點會有一段的時間(時間長短視集羣的數據量和宕機時間而定)致使整個集羣中全部節點都成爲secondary而沒法進行寫操做(若是應用程序沒有設置相應的ReadReference也可能不能進行讀取操做)。
官方推薦的最小的副本集也應該具有一個primary節點和兩個secondary節點。兩個節點的副本集不具有真正的故障轉移能力。
參考:https://www.cnblogs.com/zhoujinyi/p/3554010.html
https://www.cnblogs.com/chenmh/p/8681867.html