副本集的管理(一)

太阳11个月前技术文章310

一、以单机模式的方式启动

    当需要维护某个节点的时候,通常是以单机模式启动该节点,完成维护后再重启为集群中某节点。

    如何以单机模式启动服务器?

不指定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()

相关文章

Hbase压缩算法

HBase包含两类压缩机制:DataBlockEncode前缀压缩和文件级别的压缩Compress。对于DataBlockEncode前缀压缩,提供了三种算法:PREFIX\DIFF\FAST_DIF...

MySQL运维实战之ProxySQL(9.9)proxysql自身高可用

MySQL运维实战之ProxySQL(9.9)proxysql自身高可用

proxysql作为一个程序,本身也可能出现故障。部署proxysql的服务器也肯能出现故障。高可用架构的一个基本原则是消除单点。可以在多个节点上部署proxysql,在proxysql之前再加一层负...

Ambari集群Spark3.x动态资源分配

Ambari集群Spark3.x动态资源分配

环境节点hdp01HDP3.1.5hdp02Spark3.2.4hdp03首先Spark配置History服务配置spark-defaults.confspark.master            ...

Hive删除外部表

Hive删除外部表

删除外部表操作例:1.首先我们创建一个外部表create EXTERNAL table if not exists mgtest(id int, name string)row format deli...

MySQL 8.0 新特性:Persisted System Variables

MySQL 8.0 新特性:Persisted System Variables

一、前言MySQL 5.7 之前我们修改参数变量后,需要将其手动写入到服务端配置文件中,否则重启后又恢复原有的配置,在 8.0 中可以在 MySQL 客户端直接将参数持久化,节省在服务器操作的步骤,下...

haproxy服务无法正常启动

haproxy服务无法正常启动

【局点信息】测试环境【集群信息】【问题现象】haproxy设置配置文件后,无法正常启动,查看服务状态显示失败配置增加内容#增加如下配置 listen ApiApplicationServer   ...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。