MongoDB 副本集把SECONDARY提升為PRIMARY


事故背景

​ 線上環境有一個MongoDB副本集,由於是部署在客戶那邊本地機房,客戶誤操作把部署副本集的另外2個節點的 VM 給刪除了(並且VM已經無法恢復了)。所幸的是還有一個節點存活,登錄節點后發現這個節點是 SECONDARY,所以可能會有一部分數據丟失,而且此時已經無法對應用提供讀寫服務。此時只能停服維護,並對集群進行恢復。

​ 基於以上問題,下面對副本集恢復操作步鄹進行了記錄。

 

處理思路

  1. 對mongodb數據進行備份(防止恢復集群時出現意外導致數據丟失)。
  2. 把僅存的 SECONDARY 節點提升為 PRIMARY,刪除集群中另外2個不存活的節點,然后重新配置MongoDB副本集。
  3. 新部署2個MongoDB節點,並加入到集群中。
  4. 等待 PRIMARY 節點數據同步到另外2個新節點后,進行數據驗證,結束生產環境維護。

注意:

由於原先的集群中只存有 SECONDARY 節點,PRIMARY 節點已經丟失,所以存在部署數據沒同步到 SECONDARY 的可能。但由於PRIMARY節點的VM已經被刪,這部分未同步的數據的丟失在所難免,想恢復這部分數據只能根據自己的業務、代碼邏輯設定才有補上丟失的數據的可能性。

 

集群恢復

1、在SECONDARY節點刪除掛掉的primary節點

1.1 查看當前副本集配置

rs1:SECONDARY> rs.conf()

輸出內容:

rs1:SECONDARY> use admin
switched to db admin
rs1:SECONDARY> rs_conf = rs.config() { "_id" : "rs1", "version" : 7, "protocolVersion" : NumberLong(1), "members" : [ { "_id" : 0, "host" : "192.168.30.207:27017", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 }, { "_id" : 1, "host" : "192.168.30.213:27017", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 }, { "_id" : 2, "host" : "192.168.30.214:27017", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 } ], "settings" : { "chainingAllowed" : true, "heartbeatIntervalMillis" : 2000, "heartbeatTimeoutSecs" : 10, "electionTimeoutMillis" : 10000, "catchUpTimeoutMillis" : -1, "catchUpTakeoverDelayMillis" : 30000, "getLastErrorModes" : { }, "getLastErrorDefaults" : { "w" : 1, "wtimeout" : 0 }, "replicaSetId" : ObjectId("5f5094994a4d5004eae73e2f") } }

1.2 刪除集群成員

  • 比如要刪除members中 host 為 192.168.30.213:27017 的成員,通過rs.conf()找到成員的 _id
{
    "_id" : 1, "host" : "192.168.30.213:27017", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 },
  • 刪除 _id 為1的成員

splice的第一個參數表示要刪除的數組元素的下標

0 表示集群中成員節點的 "_id"

1 表示刪除的個數

rs1:SECONDARY> rs_conf = rs.conf()
rs1:SECONDARY> rs_conf.members.splice(0,1)

輸出內容:

rs1:SECONDARY> rs_conf.members.splice(1,1)
[
    {
        "_id" : 1, "host" : "192.168.30.213:27017", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 } ]

依照此方法刪除副本集中不存活的節點。

注意:

有一點需要注意,由於已經刪除了 _id 為1的成員,所以后面的成員的 _id 號都會減小1,與數組中元素的下標相同。

 

2、重新配置MongoDB副本集

2.1 重置集群配置

rs_conf 就是上面修改后的配置,加force參數是因為 SECONDARY 默認沒有執行此命令的權限

rs1:SECONDARY> rs.reconfig(rs_conf, {"force":true})

返回內容:

rs1:SECONDARY> rs.reconfig(rs_conf, {"force":true}) { "ok" : 1, "operationTime" : Timestamp(1619586716, 1), "$clusterTime" : { "clusterTime" : Timestamp(1619588924, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } } rs1:PRIMARY> 

2.2 查看集群狀態

rs1:PRIMARY> rs.status()

返回內容:

{
    "set" : "rs1", "date" : ISODate("2021-04-28T05:51:03.672Z"), "myState" : 1, "term" : NumberLong(17), "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "heartbeatIntervalMillis" : NumberLong(2000), "optimes" : { "lastCommittedOpTime" : { "ts" : Timestamp(1619589055, 1), "t" : NumberLong(17) }, "readConcernMajorityOpTime" : { "ts" : Timestamp(1619589055, 1), "t" : NumberLong(17) }, "appliedOpTime" : { "ts" : Timestamp(1619589055, 1), "t" : NumberLong(17) }, "durableOpTime" : { "ts" : Timestamp(1619589055, 1), "t" : NumberLong(17) } }, "members" : [ { "_id" : 0, "name" : "192.168.30.207:27017", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 7482, "optime" : { "ts" : Timestamp(1619589055, 1), "t" : NumberLong(17) }, "optimeDate" : ISODate("2021-04-28T05:50:55Z"), "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "", "electionTime" : Timestamp(1619588924, 1), "electionDate" : ISODate("2021-04-28T05:48:44Z"), "configVersion" : 124340, "self" : true, "lastHeartbeatMessage" : "" } ], "ok" : 1, "operationTime" : Timestamp(1619589055, 1), "$clusterTime" : { "clusterTime" : Timestamp(1619589055, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } }

此時發現,這個 SECONDARY 節點已經提升為 PRIMARY,並且集群狀態中,也就只有我們當前一個節點。

接下來就可以向副本集中添加新的MongoDB節點了。

 

3、添加新的MongoDB節點

這里省略新節點的部署過程,具體可以參考[《MongoDB 單節點升級為副本集高可用集群》](MongoDB 單節點升級為副本集高可用集群 - HEBIN博客 (wanhebin.com))文章中MongoDB節點部署的步鄹。

注意:

向mongodb副本集添加實例后,PRIMARY節點數據能夠自動同步到新添加的SECONDARY節點,無需人工干預。

3.1 增加實例

登錄PRIMARY節點,添加MongoDB實例。

新添加的實例優先級權重默認為1,如需調整,建議等數據同步完成后進行權重更改。

rs1:PRIMARY> use admin
rs1:PRIMARY> rs.add('192.168.30.213:27017') rs1:PRIMARY> rs.add('192.168.30.214:27017')

添加節點的返回結果如下:

rs1:PRIMARY> rs.add('192.168.30.213:27017') { "ok" : 1, "operationTime" : Timestamp(1619581966, 1), "$clusterTime" : { "clusterTime" : Timestamp(1619581966, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } } rs1:PRIMARY> rs.add('192.168.30.214:27017') { "ok" : 1, "operationTime" : Timestamp(1619581975, 1), "$clusterTime" : { "clusterTime" : Timestamp(1619581975, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } }

3.2 刪除實例

如果添加錯節點時,可以通過 rs.remove() 來刪除錯誤的節點(因為此時當前實例已經是 PRIMARY 了,所以不需要用 1.2 中方法剔除節點)。

從mongodb副本集中移除實例,不可移除primary

rs1:PRIMARY> use admin
rs1:PRIMARY> rs.remove('192.168.30.214:27017')

返回內容:

rs1:PRIMARY> rs.remove('192.168.30.213:27017') { "ok" : 1, "operationTime" : Timestamp(1619581713, 1), "$clusterTime" : { "clusterTime" : Timestamp(1619581713, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } } rs1:PRIMARY> rs.remove('192.168.30.214:27017') { "ok" : 1, "operationTime" : Timestamp(1619581777, 2), "$clusterTime" : { "clusterTime" : Timestamp(1619581777, 2), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } }

注意:

副本集經過添加刪除后順序會亂,可以根據需要設置權重來調整。

 

4、調整節點權重

如果想在集群宕機恢復后,還想讓某一節點始終保持為 PRIMARY,可以把此節點的權重設置成最大。

4.1 設置權重

找到對應節點在副本集中成員_id,進行權重設置。

這里以成員0為例,其host為192.168.30.207:27017

rs1:PRIMARY> rs_conf = rs.config()
rs1:PRIMARY> rs_conf.members[0].priority=10

4.2 生效配置

rs1:PRIMARY> rs.reconfig(rs_conf)

返回結果:

rs1:PRIMARY> rs.reconfig(rs_conf)
{
    "ok" : 1, "operationTime" : Timestamp(1619591404, 1), "$clusterTime" : { "clusterTime" : Timestamp(1619591404, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } }

4.3 驗證權重配置

  • 查詢成員0的權重
rs1:PRIMARY> rs.config()

返回內容:

{
        "_id" : 0, "host" : "192.168.30.207:27017", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 10, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 }
  • 模擬宕機恢復后的集群狀態

關閉三個節點的mongodb服務,再無序恢復,然后連接進節點192.168.30.207:27017,成員0依然還是PRIMARY。(為了必然偶然性,可以進行多次測試)

 

https://www.wanhebin.com/database/mongodb/1026.html

 


免責聲明!

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



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