实验环境
主机操作系统:ubuntu-16.04
MongoDB版本:4.0.1
server1: 192.168.225.129
server2: 192.168.225.130
server3: 192.168.225.131
副本集部署
当副本集的总可投票数为偶数时,可能出现无法选举出主节点的情况,MongoDB会提示:
replSet total number of votes is even - add arbiter or give one member an extra vote。
所以一般在生产环境中部署复制集时需要注意以下两点:
- 设置MongoDB初始节点数为奇数。
- 在集群中适当增加仲裁节点来增加集群的稳定性。(当奇数个节点挂掉一个PRIMARY节点后,集群可投票节点数变为偶数)
本次部署方案:2数据节点 + 1仲裁节点
安装步骤
1.安装mongodb
分别在3台主机上执行安装操作,具体步骤可以参考这里。
2.为primary和secondary节点创建data与log目录,并准备配置文件。
server1
#创建目录
mkdir /home/ubuntu/mongodb
mkdir /home/ubuntu/mongodb/data
mkdir /home/ubuntu/mongodb/log
创建配置文件
vim /home/ubuntu/mongdb/replset.conf
bind_ip=192.168.225.129
port=27017
dbpath=/home/ubuntu/mongodb/data
logpath=/home/ubuntu/mongodb/log/mongodb.log
logappend=true
fork=true
#repliaction
oplogSize=20
replSet=rep1
server2
#创建目录
mkdir /home/ubuntu/mongodb
mkdir /home/ubuntu/mongodb/data
mkdir /home/ubuntu/mongodb/log
创建配置文件
vim /home/ubuntu/mongdb/replset.conf
bind_ip=192.168.225.130
port=27017
dbpath=/home/ubuntu/mongodb/data
logpath=/home/ubuntu/mongodb/log/mongodb.log
logappend=true
fork=true
#repliaction
oplogSize=20
replSet=rep1
server3
#创建目录
mkdir /home/ubuntu/mongodb
mkdir /home/ubuntu/mongodb/data
mkdir /home/ubuntu/mongodb/log
创建配置文件
vim /home/ubuntu/mongdb/replset.conf
bind_ip=192.168.225.131
port=27017
dbpath=/home/ubuntu/mongodb/data
logpath=/home/ubuntu/mongodb/log/mongodb.log
logappend=true
fork=true
#repliaction
oplogSize=20
replSet=rep1
3.启动并初始化副本集
-
启动集群mongdb进程,在server1,server2,server3同时执行如下命令:
ubuntu$ mongod -f /home/ubuntu/mongodb/replset.conf 2018-09-21T01:44:25.192-0700 I CONTROL [main] Automatically disabling TLS 1.0, to force-enable TLS 1.0 specify --sslDisabledProtocols 'none' about to fork child process, waiting until server is ready for connections. forked process: 1920 child process started successfully, parent exiting
-
初始化副本集
在server1上输入mongo命令进入shell模式:ubuntu@ubuntu:~/mongodb$ mongo MongoDB shell version v4.0.1 connecting to: mongodb://127.0.0.1:27017 MongoDB server version: 4.0.1 Server has startup warnings: 2018-09-23T20:01:13.681-0700 I STORAGE [initandlisten] 2018-09-23T20:01:13.681-0700 I STORAGE [initandlisten] ** WARNING: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine 2018-09-23T20:01:14.552-0700 I CONTROL [initandlisten] >
执行初始化命令:
> use admin > config = { "_id":"rep1", "members":[ {"_id":0,"host":"192.168.225.129:27017"}, {"_id":1,"host":"192.168.225.130:27017"}, {"_id":2,"host":"192.168.225.131:27017",arbiterOnly:true} ] } > rs.initiate(config); #初始化配置
-
查看集群状态
rep1:PRIMARY> rs.status() { "set" : "rep1", "date" : ISODate("2018-09-24T04:55:54.782Z"), "myState" : 1, "term" : NumberLong(1), "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "heartbeatIntervalMillis" : NumberLong(2000), "optimes" : { "lastCommittedOpTime" : { "ts" : Timestamp(1537764949, 1), "t" : NumberLong(1) }, "readConcernMajorityOpTime" : { "ts" : Timestamp(1537764949, 1), "t" : NumberLong(1) }, "appliedOpTime" : { "ts" : Timestamp(1537764949, 1), "t" : NumberLong(1) }, "durableOpTime" : { "ts" : Timestamp(1537764949, 1), "t" : NumberLong(1) } }, "lastStableCheckpointTimestamp" : Timestamp(1537764929, 1), "members" : [ { "_id" : 0, "name" : "192.168.225.129:27017", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 536, "optime" : { "ts" : Timestamp(1537764949, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2018-09-24T04:55:49Z"), "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "", "electionTime" : Timestamp(1537764808, 1), "electionDate" : ISODate("2018-09-24T04:53:28Z"), "configVersion" : 1, "self" : true, "lastHeartbeatMessage" : "" }, { "_id" : 1, "name" : "192.168.225.130:27017", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 157, "optime" : { "ts" : Timestamp(1537764949, 1), "t" : NumberLong(1) }, "optimeDurable" : { "ts" : Timestamp(1537764949, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2018-09-24T04:55:49Z"), "optimeDurableDate" : ISODate("2018-09-24T04:55:49Z"), "lastHeartbeat" : ISODate("2018-09-24T04:55:54.559Z"), "lastHeartbeatRecv" : ISODate("2018-09-24T04:55:53.175Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "", "syncingTo" : "192.168.225.129:27017", "syncSourceHost" : "192.168.225.129:27017", "syncSourceId" : 0, "infoMessage" : "", "configVersion" : 1 }, { "_id" : 2, "name" : "192.168.225.131:27017", "health" : 1, "state" : 7, "stateStr" : "ARBITER", "uptime" : 157, "lastHeartbeat" : ISODate("2018-09-24T04:55:54.561Z"), "lastHeartbeatRecv" : ISODate("2018-09-24T04:55:53.050Z"), "pingMs" : NumberLong(1), "lastHeartbeatMessage" : "", "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "", "configVersion" : 1 } ], "ok" : 1, "operationTime" : Timestamp(1537764949, 1), "$clusterTime" : { "clusterTime" : Timestamp(1537764949, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } }
集群初始化后,节点角色如下:
192.168.225.129 PRIMARY 192.168.225.130 SECONDARY 192.168.225.131 ARBITER
4.验证
-
数据同步
PRIMARY写入数据:rep1:PRIMARY> use test switched to db test rep1:PRIMARY> db.col1.insert({"name": "lisi"}) WriteResult({ "nInserted" : 1 })
SECONDARY读取数据:
rep1:SECONDARY> use test switched to db test rep1:SECONDARY> db.col1.find({}) Error: error: { "operationTime" : Timestamp(1537765479, 1), "ok" : 0, "errmsg" : "not master and slaveOk=false", "code" : 13435, "codeName" : "NotMasterNoSlaveOk", "$clusterTime" : { "clusterTime" : Timestamp(1537765479, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } }
报错了,怎么回事?
因为初始状态下SECONDARY没有读取权限,我们给它添加上就ok了。rep1:SECONDARY> rs.slaveOk() rep1:SECONDARY> db.col1.find({}) { "_id" : ObjectId("5ba86fe5847c678ae536e51d"), "name" : "lisi" }
-
故障自动转移
模拟PRIMARY挂掉。ubuntu@ubuntu:~$ ps aux | grep mongod ubuntu 5048 1.7 7.8 1497928 119256 ? Sl 22:24 0:49 mongod -f replset.conf ubuntu 5915 0.0 0.0 14224 1012 pts/21 R+ 23:12 0:00 grep --color=auto mongod ubuntu@ubuntu:~$ kill -9 5048
查看集群状态
rep1:PRIMARY> rs.status() { "set" : "rep1", "date" : ISODate("2018-09-24T06:14:17.722Z"), "myState" : 1, "term" : NumberLong(5), "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "heartbeatIntervalMillis" : NumberLong(2000), "optimes" : { "lastCommittedOpTime" : { "ts" : Timestamp(1537769565, 1), "t" : NumberLong(4) }, "readConcernMajorityOpTime" : { "ts" : Timestamp(1537769565, 1), "t" : NumberLong(4) }, "appliedOpTime" : { "ts" : Timestamp(1537769648, 1), "t" : NumberLong(5) }, "durableOpTime" : { "ts" : Timestamp(1537769648, 1), "t" : NumberLong(5) } }, "lastStableCheckpointTimestamp" : Timestamp(1537769565, 1), "members" : [ { "_id" : 0, "name" : "192.168.225.129: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("2018-09-24T06:14:17.604Z"), "lastHeartbeatRecv" : ISODate("2018-09-24T06:12:44.525Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "Error connecting to 192.168.225.129:27017 :: caused by :: Connection refused", "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "", "configVersion" : -1 }, { "_id" : 1, "name" : "192.168.225.130:27017", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 162, "optime" : { "ts" : Timestamp(1537769648, 1), "t" : NumberLong(5) }, "optimeDate" : ISODate("2018-09-24T06:14:08Z"), "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "could not find member to sync from", "electionTime" : Timestamp(1537769577, 1), "electionDate" : ISODate("2018-09-24T06:12:57Z"), "configVersion" : 1, "self" : true, "lastHeartbeatMessage" : "" }, { "_id" : 2, "name" : "192.168.225.131:27017", "health" : 1, "state" : 7, "stateStr" : "ARBITER", "uptime" : 160, "lastHeartbeat" : ISODate("2018-09-24T06:14:17.409Z"), "lastHeartbeatRecv" : ISODate("2018-09-24T06:14:15.829Z"), "pingMs" : NumberLong(2), "lastHeartbeatMessage" : "", "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "", "configVersion" : 1 } ], "ok" : 1, "operationTime" : Timestamp(1537769648, 1), "$clusterTime" : { "clusterTime" : Timestamp(1537769648, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } }
此时,server2节点为PRIMARY,数据也能正常访问。
rep1:PRIMARY> use test switched to db test rep1:PRIMARY> db.col1.find({}) { "_id" : ObjectId("5ba86fe5847c678ae536e51d"), "name" : "lisi" }
5.更改副本集节点权重
非仲裁节点都有一个优先级的配置,范围为0 - 100, 越大的值在选举过程中优先成为主节点,默认情况下是1,为0时不能成为主节点。
权重参数可以在初始化集群的时候指定。
> config = {
"_id":"rep1",
"members":[
{"_id":0,"host":"192.168.225.129:27017", priority: 4},
{"_id":1,"host":"192.168.225.130:27017", priority: 2},
{"_id":2,"host":"192.168.225.131:27017",arbiterOnly:true}
]
}