https://gitee.com/et/ops/blob/master/MongoDB副本集配置和数据迁移实战.mdjavascript
环境:Ubuntu 16.04, MongoDB 3.6java
MongoDB 的副本集就是有自动故障恢复功能的 MongoDB 主从集群。因为 MongoDB 的主从复制功能不支持高可用,因此从 3.2 版本开始已经被废弃了,转而用副本集来代替。一个副本集总会有一个活跃节点(Primary)和若干个备份节点(Secondary),还有一个可选的一个仲裁者(Arbiter)节点来实现HA中的故障切换。git
参考官方的安装文档 https://docs.mongodb.com/manual/tutorial/install-mongodb-on-ubuntu/mongodb
$ mkdir -p /mnt/mongodb/replset
$ mongod --dbpath /mnt/mongodb/replset --port 27017 --replSet "my-repl" --bind_ip_all
$ mongo
> rs.initiate({ _id:"my-repl", members:[ {_id:0, host:"192.168.10.58:27017"}, {_id:1, host:"192.168.10.59:27017"} ] });输出结果:
{ "ok" : 1, "operationTime" : Timestamp(1523237919, 1), "$clusterTime" : { "clusterTime" : Timestamp(1523237919, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } }
> rs.conf(); { "_id" : "my-repl", "version" : 1, "protocolVersion" : NumberLong(1), "members" : [ { "_id" : 0, "host" : "192.168.10.58:27017", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 }, { "_id" : 1, "host" : "192.168.10.59: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("5acac41fded47067da446ddd") } }配置过程很是简单,能够看到在副本集成员中有0和1两个节点,此时主从两个服务器已经能够工做了,服务器0(Primary)有任何数据的变化都会同步到服务器1(Secondary)上。可是,此时的副本集只是提供了数据备份的功能,并不能达到高可用。若是要达到这一点,那么须要配置一个仲裁者节点(Arbiter)
仲裁者在 Primary 节点发生故障时,参与副本集的选举投票决定哪一个副本成为 Primary 节点。仲裁节点不保存数据也不会成为 Primary 节点。ubuntu
仲裁者一般不部署在大磁盘空间的服务器上,所以为了最小化默认建立数据,修改配置:vim
$ vim /etc/mongod.conf
storage.journal.enabled=false storage.mmapv1.smallFiles = true.
建立仲裁者目录并启动服务服务器
$ mkdir /mnt/mongodb/arbiter $ mongod --port 27017 --dbpath /mnt/mongodb/arbiter --replSet 'my-repl' --bind_ip_all
把仲裁者添加到副本集中架构
链接至 Primary 服务器app
$mongo --host 192.168.10.58
my-repl:PRIMARY> rs.addArb("192.168.10.57:27017") { "ok" : 1, "operationTime" : Timestamp(1523326877, 1), "$clusterTime" : { "clusterTime" : Timestamp(1523326877, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } }
查看副本集的效果:ide
>rs.status(); my-repl:PRIMARY> rs.status(); { "set" : "my-repl", "date" : ISODate("2018-04-10T02:21:44.826Z"), "myState" : 1, "term" : NumberLong(2), "heartbeatIntervalMillis" : NumberLong(2000), "optimes" : { "lastCommittedOpTime" : { "ts" : Timestamp(1523326895, 1), "t" : NumberLong(2) }, "readConcernMajorityOpTime" : { "ts" : Timestamp(1523326895, 1), "t" : NumberLong(2) }, "appliedOpTime" : { "ts" : Timestamp(1523326895, 1), "t" : NumberLong(2) }, "durableOpTime" : { "ts" : Timestamp(1523326895, 1), "t" : NumberLong(2) } }, "members" : [ { "_id" : 0, "name" : "192.168.10.58:27017", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 2891, "optime" : { "ts" : Timestamp(1523326895, 1), "t" : NumberLong(2) }, "optimeDate" : ISODate("2018-04-10T02:21:35Z"), "electionTime" : Timestamp(1523324284, 1), "electionDate" : ISODate("2018-04-10T01:38:04Z"), "configVersion" : 2, "self" : true }, { "_id" : 1, "name" : "192.168.10.59:27017", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 2624, "optime" : { "ts" : Timestamp(1523326895, 1), "t" : NumberLong(2) }, "optimeDurable" : { "ts" : Timestamp(1523326895, 1), "t" : NumberLong(2) }, "optimeDate" : ISODate("2018-04-10T02:21:35Z"), "optimeDurableDate" : ISODate("2018-04-10T02:21:35Z"), "lastHeartbeat" : ISODate("2018-04-10T02:21:43.080Z"), "lastHeartbeatRecv" : ISODate("2018-04-10T02:21:43.083Z"), "pingMs" : NumberLong(0), "syncingTo" : "192.168.10.58:27017", "configVersion" : 2 }, { "_id" : 2, "name" : "192.168.10.57:27017", "health" : 1, "state" : 7, "stateStr" : "ARBITER", "uptime" : 27, "lastHeartbeat" : ISODate("2018-04-10T02:21:43.079Z"), "lastHeartbeatRecv" : ISODate("2018-04-10T02:21:42.088Z"), "pingMs" : NumberLong(0), "configVersion" : 2 } ], "ok" : 1, "operationTime" : Timestamp(1523326895, 1), "$clusterTime" : { "clusterTime" : Timestamp(1523326895, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } }
能够看到状态显示:服务器0为 Primary, 服务器1为 Secondary, 服务器2为 Arbiter。
此时带有高可用的副本集已经配置完成,Arbiter 会监控 Primary 节点的运行状况,若是服务器0发生了宕机,那么仲裁者 Arbiter 节点会发起选举,最终选取多个 Secondary 中的某一个来做为 Primary 节点。咱们测试的架构中只有一个 Secondary 节点,那么此服务器1就会成为 Primary。而当服务器0恢复工做时,它会被当成 Secondary 来运行。
副本优先级
副本集会在 Primary 节点出现故障时把 Secondary 提高为 Primary,可是不少状况下 Secondary 只是做为备用节点,咱们不但愿它长期做为 Primary 节点运行。那么为了达到这个目的,咱们修改副本的优先级。
cfg = rs.conf() cfg.members[0].priority = 10 cfg.members[1].priority = 5 rs.reconfig(cfg) { "ok" : 1, "operationTime" : Timestamp(1523411797, 2), "$clusterTime" : { "clusterTime" : Timestamp(1523411797, 2), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } }
{ "ok" : 0, "errmsg" : "replSetReconfig should only be run on PRIMARY, but my state is ARBITER; use the \"force\" argument to override", "code" : 10107, "codeName" : "NotMaster" }
在配置副本集以前,你可能已经存在了一个单独的 MongoDB 实例存储了一些数据,你须要把原来实例中的数据迁移到新的副本集中。(你也能够一开始就把原来的单个实例配置成副本集的 Primary 节点,而后新增副原本同步数据,此方法不在本文讨论范围以内)
登陆原实例所在的服务器,导出数据:
$ mongoexport -h localhost -p 27017 -u xxx -p xxx -d MY_DB_NAME -c MY_COLLECTION_NAME -o MY_COLLECTION_NAME.dmp
在阿里云上测试了一个导出数据大约为1.2G大小的集合,导出性能以下:
将导出的数据文件 MY_COLLECTION_NAME.dmp 已任何方式(好比scp)同步到 Primary 节点所在的服务器0上
导入数据至副本集 Primay 节点
mongoimport -h my-repl/192.168.10.58:27017 -d MY_DB_NAME -c MY_COLLECTION_NAME --file MY_COLLECTION_NAME.dmp
测试导入性能
注意:因为不是相同的服务器,因此不能经过这个来比较导入和导出的性能差异,只能所谓一个参考:
总结: