原理很簡單一個primary,secondary至少是一個,也能夠是多個secondary,除了多個secondary以外,還能夠加一個Arbiter,Arbiter叫作仲裁,當Primary宕機後,Arbiter能夠很準確的告知Primary宕掉了,但可能Primary認爲本身沒有宕掉,這樣的話就會出現腦裂,爲了防止腦裂就增長了Arbiter這個角色,尤爲是數據庫堅定不能出現腦裂的狀態,腦裂會致使數據會紊亂,數據一旦紊亂恢復就很是麻煩.linux
說明:Primary宕機後,其中secondary就成爲一個新的Primary,另一個secondary依然是secondary的角色. 對於MySQL主歷來講,即便作一主多從,萬一master宕機後,可讓從成爲新的主,但這過程是須要手動的更改的. 可是在MongoDB副本集架構當中呢,它徹底都是自動的,rimary宕機後,其中secondary就成爲一個新的Primary,另一個secondary能夠自動識別新的primary.mongodb
準備三臺機器: 192.168.2.115 (primary)
192.168.2.116 (secondary)
192.168.2.117 (secondary)
三臺機器都須要安裝MongoDB,primary已安裝過,兩臺secondary須要安裝,因步驟同樣,在此不作演示.shell
Primary機器: [root@root-01 ~]# vim /etc/mongod.conf net: port: 27017 bindIp: 127.0.0.1,192.168.2.115 # Listen to local interface only, comment to listen on all interfaces. 說明:作副本集bindIp 要監聽本機IP和內網IP #replication: //把#去掉,並增兩行 replication: oplogSizeMB: 20 replSetName: annalinux //定義副本集的名字 重啓MongoDB服務: [root@root-01 ~]# systemctl restart mongod [root@root-01 ~]# ps aux |grep mongod mongod 39020 7.3 4.8 1016828 48880 ? Sl 17:18 0:00 /usr/bin/mongod -f /etc/mongod.conf root 39050 0.0 0.0 112664 964 pts/0 S+ 17:19 0:00 grep --color=auto mongod Secondary1機器: [root@root-02 ~]# vim /etc/mongod.conf net: port: 27017 bindIp: 127.0.0.1,192.168.2.116 # Listen to local interface only, comment to listen on all interfaces. 說明:作副本集bindIp 要監聽本機IP和內網IP #replication: //把#去掉,並增兩行 replication: oplogSizeMB: 20 replSetName: annalinux //定義副本集的名字 重啓MongoDB服務: [root@root-02 ~]# systemctl restart mongod [root@root-02 ~]# ps aux |grep mongod mongod 2303 2.2 4.6 1016336 46404 ? Sl 17:28 0:00 /usr/bin/mongod -f /etc/mongod.conf root 2331 0.0 0.0 112664 968 pts/0 S+ 17:28 0:00 grep --color=auto mongod Secondary2機器: [root@root-03 ~]# vim /etc/mongod.conf net: port: 27017 bindIp: 127.0.0.1,192.168.2.117 # Listen to local interface only, comment to listen on all interfaces. 說明:作副本集bindIp 要監聽本機IP和內網IP #replication: //把#去掉,並增兩行 replication: oplogSizeMB: 20 replSetName: annalinux //定義副本集的名字 重啓MongoDB服務: [root@root-03 ~]# systemctl restart mongod [root@root-03 ~]# ps aux |grep mongod mongod 2735 3.5 4.3 1016340 43932 ? Sl 17:46 0:00 /usr/bin/mongod -f /etc/mongod.conf root 2761 0.0 0.0 112664 968 pts/0 R+ 17:47 0:00 grep --color=auto mongod
[root@root-01 ~]# mongo MongoDB shell version v3.4.9 connecting to: mongodb://127.0.0.1:27017 MongoDB server version: 3.4.9 Server has startup warnings: 2017-10-20T17:18:53.740+0800 I CONTROL [initandlisten] 2017-10-20T17:18:53.740+0800 I CONTROL [initandlisten] ** WARNING: Access control is not enabled for the database. 2017-10-20T17:18:53.740+0800 I CONTROL [initandlisten] ** Read and write access to data and configuration is unrestricted. 2017-10-20T17:18:53.740+0800 I CONTROL [initandlisten] 2017-10-20T17:18:53.740+0800 I CONTROL [initandlisten] 2017-10-20T17:18:53.740+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'. 2017-10-20T17:18:53.740+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never' 2017-10-20T17:18:53.740+0800 I CONTROL [initandlisten] 2017-10-20T17:18:53.740+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'. 2017-10-20T17:18:53.740+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never' 2017-10-20T17:18:53.740+0800 I CONTROL [initandlisten]
說明:在哪臺機器上執行這一步,那麼哪臺機器就會成爲primary數據庫
> config={_id:"annalinux",members:[{_id:0,host:"192.168.2.115:27017"},{_id:1,host:"192.168.2.116:27017"},{_id:2,host:"192.168.2.117:27017"}]} { "_id" : "annalinux", "members" : [ { "_id" : 0, "host" : "192.168.2.115:27017" }, { "_id" : 1, "host" : "192.168.2.116:27017" }, { "_id" : 2, "host" : "192.168.2.117:27017" } ] } config={_id:"annalinux" --> annalinux(副本集的名字) members --> 指定成員
> rs.initiate(config) { "ok" : 1 }
說明:能夠看到192.168.2.115 顯示:"stateStr" : "PRIMARY"
192.168.2.116和192.168.2.117 分別顯示: "stateStr" : "SECONDARY"vim
annalinux:SECONDARY> rs.status() { "set" : "annalinux", "date" : ISODate("2017-10-20T10:02:15.484Z"), "myState" : 1, "term" : NumberLong(1), "heartbeatIntervalMillis" : NumberLong(2000), "optimes" : { "lastCommittedOpTime" : { "ts" : Timestamp(1508493732, 1), "t" : NumberLong(1) }, "appliedOpTime" : { "ts" : Timestamp(1508493732, 1), "t" : NumberLong(1) }, "durableOpTime" : { "ts" : Timestamp(1508493732, 1), "t" : NumberLong(1) } }, "members" : [ { "_id" : 0, "name" : "192.168.2.115:27017", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 2602, "optime" : { "ts" : Timestamp(1508493732, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2017-10-20T10:02:12Z"), "infoMessage" : "could not find member to sync from", "electionTime" : Timestamp(1508493631, 1), "electionDate" : ISODate("2017-10-20T10:00:31Z"), "configVersion" : 1, "self" : true }, { "_id" : 1, "name" : "192.168.2.116:27017", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 115, "optime" : { "ts" : Timestamp(1508493732, 1), "t" : NumberLong(1) }, "optimeDurable" : { "ts" : Timestamp(1508493732, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2017-10-20T10:02:12Z"), "optimeDurableDate" : ISODate("2017-10-20T10:02:12Z"), "lastHeartbeat" : ISODate("2017-10-20T10:02:13.519Z"), "lastHeartbeatRecv" : ISODate("2017-10-20T10:02:13.875Z"), "pingMs" : NumberLong(0), "syncingTo" : "192.168.2.117:27017", "configVersion" : 1 }, { "_id" : 2, "name" : "192.168.2.117:27017", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 115, "optime" : { "ts" : Timestamp(1508493732, 1), "t" : NumberLong(1) }, "optimeDurable" : { "ts" : Timestamp(1508493732, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2017-10-20T10:02:12Z"), "optimeDurableDate" : ISODate("2017-10-20T10:02:12Z"), "lastHeartbeat" : ISODate("2017-10-20T10:02:13.519Z"), "lastHeartbeatRecv" : ISODate("2017-10-20T10:02:13.881Z"), "pingMs" : NumberLong(0), "syncingTo" : "192.168.2.115:27017", "configVersion" : 1 } ], "ok" : 1 } annalinux:PRIMARY>
切換到admin庫: annalinux:PRIMARY> use admin switched to db admin 建立mydb庫: annalinux:PRIMARY> use mydb switched to db mydb 建立acc集合,並插入一些數據: annalinux:PRIMARY> db.acc.insert({AccountID:1,USerName:"123",password:"123456"}) WriteResult({ "nInserted" : 1 }) 查看全部庫: annalinux:PRIMARY> show dbs admin 0.000GB db1 0.000GB local 0.000GB mydb 0.000GB test 0.000GB 切換到mydb庫: annalinux:PRIMARY> show dbs admin 0.000GB db1 0.000GB local 0.000GB mydb 0.000GB test 0.000GB 進入mydb庫: annalinux:PRIMARY> use mydb switched to db mydb 查看集合: annalinux:PRIMARY> show tables acc
說明: 和primary機器數據一致,說明搭建副本集成功了bash
登陸: [root@root-02 ~]# mongo MongoDB shell version v3.4.9 connecting to: mongodb://127.0.0.1:27017 MongoDB server version: 3.4.9 Welcome to the MongoDB shell. For interactive help, type "help". For more comprehensive documentation, see http://docs.mongodb.org/ Questions? Try the support group http://groups.google.com/group/mongodb-user Server has startup warnings: 2017-10-20T17:28:02.614+0800 I CONTROL [initandlisten] 2017-10-20T17:28:02.614+0800 I CONTROL [initandlisten] ** WARNING: Access control is not enabled for the database. 2017-10-20T17:28:02.614+0800 I CONTROL [initandlisten] ** Read and write access to data and configuration is unrestricted. 2017-10-20T17:28:02.614+0800 I CONTROL [initandlisten] 2017-10-20T17:28:02.614+0800 I CONTROL [initandlisten] 2017-10-20T17:28:02.614+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'. 2017-10-20T17:28:02.614+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never' 2017-10-20T17:28:02.614+0800 I CONTROL [initandlisten] 2017-10-20T17:28:02.614+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'. 2017-10-20T17:28:02.614+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never' 2017-10-20T17:28:02.614+0800 I CONTROL [initandlisten] 查看全部庫: annalinux:SECONDARY> show dbs; 2017-10-20T18:18:50.600+0800 E QUERY [thread1] Error: listDatabases failed:{ "ok" : 0, "errmsg" : "not master and slaveOk=false", //提示不是master,slaveOK=false "code" : 13435, "codeName" : "NotMasterNoSlaveOk" } : _getErrorWithCode@src/mongo/shell/utils.js:25:13 Mongo.prototype.getDBs@src/mongo/shell/mongo.js:62:1 shellHelper.show@src/mongo/shell/utils.js:769:19 shellHelper@src/mongo/shell/utils.js:659:15 @(shellhelp2):1:1 須要執行: annalinux:SECONDARY> rs.slaveOk() 再show dbs就沒問題: annalinux:SECONDARY> show dbs; admin 0.000GB db1 0.000GB local 0.000GB mydb 0.000GB test 0.000GB 進入mydb庫: annalinux:SECONDARY> use mydb switched to db mydb 查看集合: annalinux:SECONDARY> show tables acc
說明: 和primary機器數據一致,說明搭建副本集成功了架構
[root@root-03 ~]# mongo MongoDB shell version v3.4.9 connecting to: mongodb://127.0.0.1:27017 MongoDB server version: 3.4.9 Welcome to the MongoDB shell. For interactive help, type "help". For more comprehensive documentation, see http://docs.mongodb.org/ Questions? Try the support group http://groups.google.com/group/mongodb-user Server has startup warnings: 2017-10-20T17:46:53.757+0800 I CONTROL [initandlisten] 2017-10-20T17:46:53.757+0800 I CONTROL [initandlisten] ** WARNING: Access control is not enabled for the database. 2017-10-20T17:46:53.757+0800 I CONTROL [initandlisten] ** Read and write access to data and configuration is unrestricted. 2017-10-20T17:46:53.757+0800 I CONTROL [initandlisten] 2017-10-20T17:46:53.757+0800 I CONTROL [initandlisten] 2017-10-20T17:46:53.757+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'. 2017-10-20T17:46:53.757+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never' 2017-10-20T17:46:53.757+0800 I CONTROL [initandlisten] 2017-10-20T17:46:53.757+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'. 2017-10-20T17:46:53.758+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never' 2017-10-20T17:46:53.758+0800 I CONTROL [initandlisten] 查看全部庫: annalinux:SECONDARY> show dbs; 2017-10-20T18:18:50.600+0800 E QUERY [thread1] Error: listDatabases failed:{ "ok" : 0, "errmsg" : "not master and slaveOk=false", //提示不是master,slaveOK=false "code" : 13435, "codeName" : "NotMasterNoSlaveOk" } : _getErrorWithCode@src/mongo/shell/utils.js:25:13 Mongo.prototype.getDBs@src/mongo/shell/mongo.js:62:1 shellHelper.show@src/mongo/shell/utils.js:769:19 shellHelper@src/mongo/shell/utils.js:659:15 @(shellhelp2):1:1 須要執行: annalinux:SECONDARY> rs.slaveOk() 再show dbs就沒問題: annalinux:SECONDARY> show dbs; admin 0.000GB db1 0.000GB local 0.000GB mydb 0.000GB test 0.000GB 進入mydb庫: annalinux:SECONDARY> use mydb switched to db mydb 查看集合: annalinux:SECONDARY> show tables acc
說明:在primary機器添加防火牆規則,僞裝primary宕機,看看是如何變成一個新的primary。app
說明:能夠看到三個節點都是"priority" : 1, 也就是說三個節點權重都是同樣負載均衡
annalinux:PRIMARY> rs.config() { "_id" : "annalinux", "version" : 1, "protocolVersion" : NumberLong(1), "members" : [ { "_id" : 0, "host" : "192.168.2.115:27017", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 }, { "_id" : 1, "host" : "192.168.2.116:27017", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 }, { "_id" : 2, "host" : "192.168.2.117: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" : 60000, "getLastErrorModes" : { }, "getLastErrorDefaults" : { "w" : 1, "wtimeout" : 0 }, "replicaSetId" : ObjectId("59e9c9342025e71e7bcebc7b") } }
[root@root-01 ~]# iptables -I INPUT -p tcp --dport 27017 -j DROP
說明: 本來192.168.2.115是primary,如今192.168.2.117變成了primarytcp
查看副本集狀態: annalinux:SECONDARY> rs.status() { "set" : "annalinux", "date" : ISODate("2017-10-20T10:40:27.907Z"), "myState" : 2, "term" : NumberLong(2), "syncingTo" : "192.168.2.117:27017", "heartbeatIntervalMillis" : NumberLong(2000), "optimes" : { "lastCommittedOpTime" : { "ts" : Timestamp(1508496022, 1), "t" : NumberLong(2) }, "appliedOpTime" : { "ts" : Timestamp(1508496022, 1), "t" : NumberLong(2) }, "durableOpTime" : { "ts" : Timestamp(1508496022, 1), "t" : NumberLong(2) } }, "members" : [ { "_id" : 0, "name" : "192.168.2.115:27017", "health" : 0, "state" : 8, "stateStr" : "(not reachable/healthy)", //顯示不能獲取狀態值 "uptime" : 0, "optime" : { "ts" : Timestamp(0, 0), "t" : NumberLong(-1) }, "optimeDurable" : { "ts" : Timestamp(0, 0), "t" : NumberLong(-1) }, "optimeDate" : ISODate("1970-01-01T00:00:00Z"), "optimeDurableDate" : ISODate("1970-01-01T00:00:00Z"), "lastHeartbeat" : ISODate("2017-10-20T10:40:26.805Z"), "lastHeartbeatRecv" : ISODate("2017-10-20T10:40:27.796Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "Couldn't get a connection within the time limit", "configVersion" : -1 }, { "_id" : 1, "name" : "192.168.2.116:27017", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 4345, "optime" : { "ts" : Timestamp(1508496022, 1), "t" : NumberLong(2) }, "optimeDate" : ISODate("2017-10-20T10:40:22Z"), "syncingTo" : "192.168.2.117:27017", "configVersion" : 1, "self" : true }, { "_id" : 2, "name" : "192.168.2.117:27017", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 2405, "optime" : { "ts" : Timestamp(1508496022, 1), "t" : NumberLong(2) }, "optimeDurable" : { "ts" : Timestamp(1508496022, 1), "t" : NumberLong(2) }, "optimeDate" : ISODate("2017-10-20T10:40:22Z"), "optimeDurableDate" : ISODate("2017-10-20T10:40:22Z"), "lastHeartbeat" : ISODate("2017-10-20T10:40:26.709Z"), "lastHeartbeatRecv" : ISODate("2017-10-20T10:40:26.089Z"), "pingMs" : NumberLong(0), "electionTime" : Timestamp(1508495934, 1), "electionDate" : ISODate("2017-10-20T10:38:54Z"), "configVersion" : 1 } ], "ok" : 1 }
說明:把在原來的primary機器設置的iptables規則刪除掉,它也不能變會primary,除非設置了權重
[root@root-01 ~]# iptables -D INPUT -p tcp --dport 27017 -j DROP
設置變量: annalinux:PRIMARY> cfg=rs.config() { "_id" : "annalinux", "version" : 1, "protocolVersion" : NumberLong(1), "members" : [ { "_id" : 0, "host" : "192.168.2.115:27017", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 }, { "_id" : 1, "host" : "192.168.2.116:27017", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 }, { "_id" : 2, "host" : "192.168.2.117: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" : 60000, "getLastErrorModes" : { }, "getLastErrorDefaults" : { "w" : 1, "wtimeout" : 0 }, "replicaSetId" : ObjectId("59e9c9342025e71e7bcebc7b") } } 設置權重: annalinux:PRIMARY> cfg.members[0].priority=3 3 annalinux:PRIMARY> cfg.members[1].priority=2 2 annalinux:PRIMARY> cfg.members[2].priority=1 1 讓設置的權重生效: annalinux:PRIMARY> rs.reconfig(cfg) { "ok" : 1 } 查看權重: annalinux:PRIMARY> rs.config() 2017-10-20T18:54:07.529+0800 E QUERY [thread1] Error: error doing query: failed: network error while attempting to run command 'replSetGetConfig' on host '127.0.0.1:27017' : DB.prototype.runCommand@src/mongo/shell/db.js:132:1 DB.prototype.adminCommand@src/mongo/shell/db.js:150:16 rs.conf@src/mongo/shell/utils.js:1271:16 @(shell):1:1 2017-10-20T18:54:07.533+0800 I NETWORK [thread1] trying reconnect to 127.0.0.1:27017 (127.0.0.1) failed 2017-10-20T18:54:07.534+0800 I NETWORK [thread1] reconnect 127.0.0.1:27017 (127.0.0.1) ok annalinux:SECONDARY> 說明: 提示這臺機器不是primary,已經發生了改變,這臺機器變成了Secondary了 從新執行rs.config(): annalinux:SECONDARY> rs.config() { "_id" : "annalinux", "version" : 2, "protocolVersion" : NumberLong(1), "members" : [ { "_id" : 0, "host" : "192.168.2.115:27017", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 3, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 }, { "_id" : 1, "host" : "192.168.2.116:27017", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 2, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 }, { "_id" : 2, "host" : "192.168.2.117: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" : 60000, "getLastErrorModes" : { }, "getLastErrorDefaults" : { "w" : 1, "wtimeout" : 0 }, "replicaSetId" : ObjectId("59e9c9342025e71e7bcebc7b") } } 說明:能夠看到192.168.2.115的權重顯示: "priority" : 3 192.168.2.116的權重顯示: "priority" : 2 192.168.2.117的權重顯示: "priority" : 1