副本集的管理(一)
一、以单机模式的方式启动
当需要维护某个节点的时候,通常是以单机模式启动该节点,完成维护后再重启为集群中某节点。
如何以单机模式启动服务器?
不指定replset选项 dbpath保持不变 port使用非原端口 mongod --port=xxx --dbpath=xxx
二、副本集配置
1、创建副本集
创建一个新副本集最常用的方法是先将配置信息定义为一个参数,然后使用该参数进行初始化。
cnf = {"_id":"rs0","members":[ ... {"_id":1,"host":"192.168.1.73:28000","priority":1 }, ... {"_id":2, "host":"192.168.1.73:28001","priority":1}, ... {"_id":3, "host":"192.168.1.73:28002","priority":1}]} rs.initiate(cnf)
2、修改副本集成员
1)新增
方法一: rs.add("192.168.1.73:28000") rs.add({"_id":5,"host":"192.168.1.73:28000","priority":0,"hidden":true}) 方法二:(修改配置文件) config = rs.config() config.members[0].host = "xx:xx" rs.reconfig(config)
修改配置文件需要注意到几点:
1.不能修改成员的"_id"字段 2.不能修改成员的priority为0 3.不能将仲裁者节点变更为非仲裁者节点 4.不能将"buildIndexes":"false"的成员修改为true
2)删除
rs.remove("192.168.1.73:28000")
3、强制重新配置
当副本集自身无法达到“大多数”原则来进行选举主节点时,可以强制重新配置副本集
rs.reconfig(config,{"froce":true})
4、创建比较大的副本集
当创建副本集节点数比较多的时候,主节点需要每次需要心跳检测来判断自己是否复合“大多数”。这种情况下,心跳的网络流量和选举所花费的时间都会比较大。为避免这种情况我们可以指定某几个节点具体选举的权利。
rs.add({"_id":4,"host":"xx:xx","votes":0})
三、修改副本集成员状态
1、把主节点变为备份节点
rs.stepDown(600) //10分钟
不指定时间的情况下默认60秒内不会有新的主被选举出来。
2、维护主节点时阻止选举
rs.freeze(600)
强制执行该命令的节点在10分钟内被选举为主节点。
3、使用维护模式
当某个节点执行一个非常耗时的操作时,该节点就会自动进入RECOVERING状态,避免在该节点上读取到比较旧的数据。同样,如果一个节点复制比较落后的情况下,我们可以强制该节点进入RECOVERING状态,避免在该节点读取数据的同时,该节点也不能继续为别的节点的复制源
四、监控复制
1、获取状态
rs0:PRIMARY> rs.status() { "set" : "rs0", "date" : ISODate("2018-11-08T07:29:05.825Z"), "myState" : 1, "members" : [ { "_id" : 1, "name" : "172.21.86.228:28000", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", //该节点的状态 "uptime" : 170842, //从可达到现在所经历的时间 "optime" : Timestamp(1541649203, 2), "optimeDate" : //oplog中最后一次操作发生的时间 ISODate("2018-11-08T03:53:23Z"), "electionTime" : Timestamp(1541491499, 1), "electionDate" : ISODate("2018-11-06T08:04:59Z"), "configVersion" : 1, "self" : true //执行本命令的节点才会显示该参数 }, { "_id" : 2, "name" : "172.21.86.228:28001", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 170650, "optime" : Timestamp(1541649203, 2), "optimeDate" : ISODate("2018-11-08T03:53:23Z"), "lastHeartbeat" : //最后一次心跳检测的时间 ISODate("2018-11-08T07:29:05.819Z"), "lastHeartbeatRecv" : ISODate("2018-11-08T07:29:05.626Z"), "pingMs" : 0, //从当前服务器到达某节点花费的平均时间 "syncingTo" : "172.21.86.228:28000", //同步源 "configVersion" : 1 }, { "_id" : 3, "name" : "172.21.86.228:28002", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 170650, "optime" : Timestamp(1541649203, 2), "optimeDate" : ISODate("2018-11-08T03:53:23Z"), "lastHeartbeat" : ISODate("2018-11-08T07:29:05.819Z"), "lastHeartbeatRecv" : ISODate("2018-11-08T07:29:05.626Z"), "pingMs" : 0, "syncingTo" : "172.21.86.228:28000", "configVersion" : 1 } ], "ok" : 1 }
2、复制循环
复制循环就是值A-->B,B-->C,C-->A。出现这种情况是复制往往会越来越落后,这时我们可以手动指定复制源来避免这种情况。
3、禁止使用复制链
禁止使用复制链就意味着所有的备份节点都要从主节点来进行复制,只有主节点不可用时才会从别的备份节点来进行复制。
config = rs.config() config.settings = config.settings || {} config.settings.allowChaining = false re.reconfig(config)
4、计算延迟
1)可以使用rs.status()来查看复制的状态
infoMessage可以看到当前复制有没有出现报错
"members" : [ { "_id" : 2, "name" : "172.16.8.141:28001", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 930, "optime" : { "ts" : Timestamp(1557407484, 1), "t" : NumberLong(12) }, "optimeDurable" : { "ts" : Timestamp(1557407484, 1), "t" : NumberLong(12) }, "optimeDate" : ISODate("2019-05-09T13:11:24Z"), "optimeDurableDate" : ISODate("2019-05-09T13:11:24Z"), "lastHeartbeat" : ISODate("2019-05-09T13:11:28.590Z"), "lastHeartbeatRecv" : ISODate("2019-05-09T13:11:28.314Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "", "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "", "electionTime" : Timestamp(1557320315, 1), "electionDate" : ISODate("2019-05-08T12:58:35Z"), "configVersion" : 5 }, { "_id" : 3, "name" : "172.16.8.141:28002", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 930, "optime" : { "ts" : Timestamp(1557407484, 1), "t" : NumberLong(12) }, "optimeDurable" : { "ts" : Timestamp(1557407484, 1), "t" : NumberLong(12) }, "optimeDate" : ISODate("2019-05-09T13:11:24Z"), "optimeDurableDate" : ISODate("2019-05-09T13:11:24Z"), "lastHeartbeat" : ISODate("2019-05-09T13:11:28.618Z"), "lastHeartbeatRecv" : ISODate("2019-05-09T13:11:27.325Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "", "syncingTo" : "172.16.8.141:28001", "syncSourceHost" : "172.16.8.141:28001", "syncSourceId" : 2, "infoMessage" : "", "configVersion" : 5 }, { "_id" : 4, "name" : "172.16.8.141:28000", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 932, "optime" : { "ts" : Timestamp(1557406333, 1), "t" : NumberLong(-1) }, "optimeDate" : ISODate("2019-05-09T12:52:13Z"), "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "sync producer problem: Location40414: BSON field 'OplogEntryBase.op' is missing but a required field", "configVersion" : 5, "self" : true, "lastHeartbeatMessage" : "" } ],
2)在主节点上执行 db.printReplicationInfo()来查看oplog的相关信息,在备份节点上执行db.printSlaveReplicationInfo()查看当前的复制源,以及落后的情况。
rs0:SECONDARY> rs.printSlaveReplicationInfo() source: 172.16.8.141:28002 syncedTo: Thu May 09 2019 21:10:44 GMT+0800 (CST) 0 secs (0 hrs) behind the primary //该节点复制正常 source: 172.16.8.141:28000 syncedTo: Thu May 09 2019 20:52:13 GMT+0800 (CST) 1111 secs (0.31 hrs) behind the primary //该节点复制粗线延迟
oplog中第一条操作与最后一条操作的时间差就是操作日志的长度。
副本集成员的延迟是相对主节点来说的,并不表示需要多长时间才能更新到最新。在一个写操作非常少的系统中,显示的“延迟”可能过大。但是可能该节点只需要几毫秒就可以追上主节点。
rs0:PRIMARY> db.test1.insert({"name":"aa","age":123}) WriteResult({ "nInserted" : 1 }) rs0:PRIMARY> db.printReplicationInfo() configured oplog size: 1000MB log length start to end: 180191secs (50.05hrs) oplog first event time: Tue Nov 06 2018 16:04:55 GMT+0800 (CST) oplog last event time: Thu Nov 08 2018 18:08:06 GMT+0800 (CST) now: Thu Nov 08 2018 18:08:10 GMT+0800 (CST) rs0:SECONDARY> db.printSlaveReplicationInfo() source: 172.21.86.228:28001 syncedTo: Thu Nov 08 2018 18:08:06 GMT+0800 (CST) 0 secs (0 hrs) behind the primary source: 172.21.86.228:28002 syncedTo: Thu Nov 08 2018 18:08:06 GMT+0800 (CST) 0 secs (0 hrs) behind the primary
5、调整oplog的大小
1.如果该节点是主节点,需要先让主节点退位,以便让其他成员可以尽快更新到与它一致
rs.stepDown()
2.关闭当前服务器
SECONDARY> db.shutdownServer()
mongod -f monogo.conf --shutdown
3.将当前服务器以单机模式启动
修改配置文件中的port/repl信息 # /opt/mongo-official3.2/bin/mongod -f /usr/local/repl1/conf/monogod.conf
4.保存oplog最后一条更新记录到一个临时的集合中
>use local >db.optmp.drop() ---清空临时表,存放oplog最近一条记录 >db.optmp.save(db.oplog.rs.find( { }, { ts: 1, h: 1 } ).sort( {$natural : -1} ).limit(1).next() ) ---将最近一条记录存放到临时集合中 >db.optmp.find() ---验证是否记录已存入 { "_id" : ObjectId("5a0d437ed4738d194fa0b94f"), "ts" : Timestamp(1510389543, 1), "h" : NumberLong("-2633465233485407995") }
5.删除当前的oplog
>use local >db.oplog.rs.drop()
6.创建一个新的oplog
> db.runCommand( { create: "oplog.rs", capped: true, size: (70 * 1024 * 1024) } ) --单位为字节 { "ok" : 1 } ---成功的话将返回ok
7.将最后一条记录写回oplog
> db.oplog.rs.save(db.optmp.findOne()) > db.oplog.rs.find() ---查询验证是否已插入
8.以副本集成员的模式重新启动服务器
修改配置文件中的port/repl信息 # /opt/mongo-official3.2/bin/mongod -f /usr/local/repl1/conf/monogod.conf
在MongoDB3.6版本中,已经实现了动态修改oplogsize参数的大小
1.查看当前oplog大小
> use local switched to db local > db.oplog.rs.stats().maxSize NumberLong(1073741824) ---单位bytes,即2014MB
2.通过管理命令修改大小
> use local switched to db local > db.adminCommand({replSetResizeOplog:1, size: 2048}); ---2048的单位也MB { "ok" : 1, "operationTime" : Timestamp(1537776585, 1), "$clusterTime" : { "clusterTime" : Timestamp(1537776585, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } }
3.验证是否修改成功
> db.oplog.rs.stats().maxSize NumberLong("2147483648")
值得注意的是,这种修改oplog的方法仅适合3.6版本之前,3.6版本之后可以通过命令行在线修改,如果重写oplog,方法略有不同,详细参考修改oplog演示。
3.6版本的报错:
"infoMessage" : "sync producer problem: Location40414: BSON field 'OplogEntryBase.op' is missing but a required field",
6、创建索引
创建索引是一个很消耗资源的操作,可能会导致服务器进入RECOVERING的状态,所以我们如果需要创建索引的话,可能需要如下步骤:
1.关闭某一个需要创建索引的备份节点 2.以单机模式启动该节点 3.创建索引 4.以副本集模式启动该节点 5.重复1-4操作对所有备份节点进行操作 6.对主节点进行创建索引 1)在一个空间的时间段对该主节点进行添加索引 2)让该主节点退位为备份节点,重复1-4操作,创建完索引之后重新将该服务器添加到副本集 后台创建索引: db.xx.createIndex({"aa": 1, "bb": 1}, {background: true})
7、主节点如何跟踪延迟
rs.status()