復制集(replica Set)或者副本集是MongoDB的核心高可用特性之一,它基於主節點的oplog日志持續傳送到輔助節點,並重放得以實現主從節點一致。再結合心跳機制,當感知到主節點不可訪問或宕機的情形下,輔助節點通過選舉機制來從剩余的輔助節點中推選一個新的主節點從而實現自動切換。對於一個已經存在的MongoDB Replica Set集群,可以對其進行節點的增加,刪除,以及修改節點屬性等等。本文即是圍繞這些進行描述。
有關MongoDB復制集概念及其搭建,可以參考:MongoDB 復制集(Replica Set)
一、節點的移除
//當前的演示環境 repSetTest:PRIMARY> db.version() 3.2.11 //主從節點 PRIMARY: localhost:27001 SECONDARY: localhost:27000 SECONDARY: localhost:27002 repSetTest:PRIMARY> rs.remove("localhost:27000") { "ok" : 1 } //移除節點后的狀態信息 repSetTest:PRIMARY> rs.status() { "set" : "repSetTest", "date" : ISODate("2016-08-30T05:48:13.010Z"), "myState" : 1, "members" : [ { "_id" : 1, "name" : "localhost:27001", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 526, "optime" : Timestamp(1472536085, 1), "optimeDate" : ISODate("2016-08-30T05:48:05Z"), "electionTime" : Timestamp(1472535890, 1), "electionDate" : ISODate("2016-08-30T05:44:50Z"), "configVersion" : 2, "self" : true }, { "_id" : 2, "name" : "localhost:27002", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 426, "optime" : Timestamp(1472536085, 1), "optimeDate" : ISODate("2016-08-30T05:48:05Z"), "lastHeartbeat" : ISODate("2016-08-30T05:48:11.805Z"), "lastHeartbeatRecv" : ISODate("2016-08-30T05:48:12.877Z"), "pingMs" : 0, "syncingTo" : "localhost:27001", "configVersion" : 2 } ], "ok" : 1 } //移除后查看配置文件 //此時版本version為2,只有2個節點 repSetTest:PRIMARY> rs.config() { "_id" : "repSetTest", "version" : 2, "members" : [ { "_id" : 1, "host" : "localhost:27001", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "slaveDelay" : 0, "votes" : 1 }, { "_id" : 2, "host" : "localhost:27002", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "slaveDelay" : 0, "votes" : 1 } ], "settings" : { "chainingAllowed" : true, "heartbeatTimeoutSecs" : 10, "getLastErrorModes" : { }, "getLastErrorDefaults" : { "w" : 1, "wtimeout" : 0 } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
二、節點的增加
repSetTest:PRIMARY> rs.add("localhost:27000") { "ok" : 1 } repSetTest:PRIMARY> rs.status() { "set" : "repSetTest", "date" : ISODate("2016-08-30T05:50:56.678Z"),6 "myState" : 1, "members" : [ { "_id" : 1, "name" : "localhost:27001", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 689, "optime" : Timestamp(1472536231, 1), "optimeDate" : ISODate("2016-08-30T05:50:31Z"), "electionTime" : Timestamp(1472535890, 1), "electionDate" : ISODate("2016-08-30T05:44:50Z"), "configVersion" : 3, "self" : true }, { "_id" : 2, "name" : "localhost:27002", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 590, "optime" : Timestamp(1472536231, 1), "optimeDate" : ISODate("2016-08-30T05:50:31Z"), "lastHeartbeat" : ISODate("2016-08-30T05:50:55.336Z"), "lastHeartbeatRecv" : ISODate("2016-08-30T05:50:55.063Z"), "pingMs" : 0, "configVersion" : 3 }, { "_id" : 3, "name" : "localhost:27000", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", //增加后的節點此時作為一個從節點 "uptime" : 23, "optime" : Timestamp(1472536231, 1), "optimeDate" : ISODate("2016-08-30T05:50:31Z"), "lastHeartbeat" : ISODate("2016-08-30T05:50:55.342Z"), "lastHeartbeatRecv" : ISODate("2016-08-30T05:50:55.341Z"), "pingMs" : 0, "configVersion" : 3 } ], "ok" : 1 }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
三、啟用Arbiter節點
repSetTest:PRIMARY> rs.remove("localhost:27000") { "ok" : 1 } repSetTest:PRIMARY> rs.add({host:"localhost:27000",arbiterOnly:true}) { "ok" : 1 } repSetTest:PRIMARY> rs.config() { "_id" : "repSetTest", "version" : 5, "members" : [ { "_id" : 1, "host" : "localhost:27001", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, // Author : Leshami "priority" : 1, // Blog : http://blog.csdn.net/leshami "tags" : { }, "slaveDelay" : 0, "votes" : 1 }, { "_id" : 2, "host" : "localhost:27002", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "slaveDelay" : 0, "votes" : 1 }, { "_id" : 3, "host" : "localhost:27000", "arbiterOnly" : true, //此處表明當前結點為仲裁節點 "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "slaveDelay" : 0, "votes" : 1 } ], "settings" : { "chainingAllowed" : true, "heartbeatTimeoutSecs" : 10, "getLastErrorModes" : { }, "getLastErrorDefaults" : { "w" : 1, "wtimeout" : 0 } } } 對於Arbiter也可以使用rs.addArb函數來添加 如:> rs.addArb("localhost:27000") 驗證仲裁節點數據寫入 repSetTest:PRIMARY> use tempdb switched to db tempdb repSetTest:PRIMARY> db.users.insert({id:1,ename:"robin"}) WriteResult({ "nInserted" : 1 }) # mongo localhost:27000 MongoDB shell version: 3.0.12 connecting to: localhost:27000/test repSetTest:ARBITER> show dbs; 2016-08-30T14:26:26.753+0800 E QUERY Error: listDatabases failed: { "note" : "from execCommand", "ok" : 0, "errmsg" : "not master" } at Error (<anonymous>) at Mongo.getDBs (src/mongo/shell/mongo.js:47:15) at shellHelper.show (src/mongo/shell/utils.js:630:33) at shellHelper (src/mongo/shell/utils.js:524:36) at (shellhelp2):1:1 at src/mongo/shell/mongo.js:47 repSetTest:ARBITER> rs.slaveOk(true) repSetTest:ARBITER> show dbs; //執行該命令,看不到tempdb local 0.281GB test 0.031GB repSetTest:ARBITER> use tempdb switched to db tempdb repSetTest:ARBITER> db.users.count() //執行count,提示節點正在恢復 2016-08-30T14:30:04.571+0800 E QUERY Error: count failed: { "note" : "from execCommand", "ok" : 0, "errmsg" : "node is recovering" } at Error (<anonymous>) at DBQuery.count (src/mongo/shell/query.js:326:11) at DBCollection.count (src/mongo/shell/collection.js:1046:27) at (shell):1:10 at src/mongo/shell/query.js:326
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
四、設定節點的優先級別(Priority)
優先級用於確定一個傾向成為主節點的程度。取值范圍為0-100
Priority 0節點的選舉優先級為0,不會被選舉為Primary,這樣的成員稱為被動成員
對於跨機房復制集的情形,如A,B機房,最好將『大多數』節點部署在首選機房,以確保能選擇合適的Primary
對於Priority為0節點的情況,通常作為一個standby,或由於硬件配置較差,設置為0以使用不可能成為主
//如下示例,在新增節點的時候設定該節點的優先級別
repSetTest:PRIMARY> rs.add({"_id":3,"host":"localhost:27000","priority":1.5})
也可以通過下面的方式修改優先級別
repSetTest:PRIMARY> var config=rs.config()
repSetTest:PRIMARY> config.members[2].priority=2
2
repSetTest:PRIMARY> rs.reconfig(config)
{ "ok" : 1 }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
五、投票節點(Vote)
投票節點不保存數據副本,不可能成為主節點
Mongodb 3.0里,復制集成員最多50個,參與Primary選舉投票的成員最多7個
對於超出7個的其他成員(Vote0)的vote屬性必須設置為0,即不參與投票
- 1
- 2
- 3
- 4
六、隱藏節點(Hidden)
Hidden節點不能被選為主(Priority為0),並且對Driver不可見。
因Hidden節點不會接受Driver的請求,可使用Hidden節點做一些數據備份、離線計算的任務,不會影響復制集的服務
隱藏節點成員建議總是將其優先級設置為0(priority 0)
由於對Driver不可見,因此不會作為read preference節點,隱藏節點可以作為投票節點
在分片集群當中,mongos不會同隱藏節點交互
> cfg = rs.conf()
> cfg.members[2].priority = 0
> cfg.members[2].hidden = true
> rs.reconfig(cfg)
查看設置為隱藏階段后的屬性
repSetTest:SECONDARY> db.isMaster()
{
"hosts" : [
"localhost:27000",
"localhost:27001"
],
"setName" : "repSetTest",
"setVersion" : 2,
"ismaster" : false,
"secondary" : true,
"primary" : "localhost:27000",
"passive" : true,
"hidden" : true, //此處表明當前節點為隱藏節點
"me" : "localhost:27002",
"maxBsonObjectSize" : 16777216,
"maxMessageSizeBytes" : 48000000,
"maxWriteBatchSize" : 1000,
"localTime" : ISODate("2017-03-06T10:15:48.257Z"),
"maxWireVersion" : 4,
"minWireVersion" : 0,
"ok" : 1
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
七、延遲節點(Delayed)
延遲節點包含復制集的部分數據,是復制集數據的子集
延遲節點上的數據通常落后於Primary一段時間(可配置,比如1個小時)。
當人為錯誤或者無效的數據寫入Primary時,可通過Delayed節點的數據進行回滾
延遲節點的要求:
優先級別為0(priority 0),避免參與primary選舉
應當設置為隱藏節點(以避免應用程序查詢延遲節點)
可以作為一個投票節點,設置 members[n].votes 值為1
延遲節點注意事項:
延遲時間應當等於和大於維護窗口持續期
應當小於oplog容納數據的時間窗口
> cfg = rs.conf()
> cfg.members[2].priority = 0
> cfg.members[2].hidden = true
> cfg.members[2].slaveDelay = 3600
> rs.reconfig(cfg)
repSetTest:SECONDARY> db.isMaster()
{
"hosts" : [
"localhost:27000",
"localhost:27001"
],
"setName" : "repSetTest",
"setVersion" : 3,
"ismaster" : false,
"secondary" : true,
"primary" : "localhost:27000",
"passive" : true,
"hidden" : true,
"slaveDelay" : 3600, //此處表面當前節點具有延遲屬性,為延遲節點
"me" : "localhost:27002",
"maxBsonObjectSize" : 16777216,
"maxMessageSizeBytes" : 48000000,
"maxWriteBatchSize" : 1000,
"localTime" : ISODate("2017-03-06T10:19:57.148Z"),
"maxWireVersion" : 4,
"minWireVersion" : 0,
"ok" : 1
}
