Mongodb 副本集多节点的高可用、切换、修复
一、Mongodb副本集群
1. MongoDB 复制(副本集)
- MongoDB复制是将数据同步在多个服务器的过程。
-
复制提供了数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性, 并可以保证数据的安全性。
-
复制还允许您从硬件故障和服务中断中恢复数据。
-
什么是复制?
保障数据的安全性
数据高可用性 (24*7)
灾难恢复
无需停机维护(如备份,重建索引,压缩)
分布式读取数据
2. MongoDB复制原理
-
mongodb的复制至少需要两个节点。其中一个是主节点,负责处理客户端请求,其余的都是从节点,负责复制主节点上的数据。
-
mongodb各个节点常见的搭配方式为:一主一从、一主多从。
-
主节点记录在其上的所有操作oplog,从节点定期轮询主节点获取这些操作,然后对自己的数据副本执行这些操作,从而保证从节点的数据与主节点一致。
3. 常见报错
- 1. 没有以集群方式启动
报错:This node was not started with the replSet option
方案:使用 “--replSet 集合名” 或 配置文件方式启动
# 使用 “--replSet 集合名” 启动mongodb集群方式
mongod -f /mongodb/27017/conf/mongo.conf --replSet dba
# 使用配置文件方式
使用配置文件启动mongodb集群方式
配置文件如下
-----------------
storage:
dbPath: "/mongodb/data/"
journal:
enabled: true
systemLog:
destination: file
logAppend: true
path: "/mongodb/log/mongod.log"
processManagement:
fork: true
net:
port: 27017
bindIp: 10.0.0.7,127.0.0.1
replication:
oplogSizeMB: 1024
replSetName: dba
# 注意不能漏""符号,bindIP不能写错。否则无法启动。
- 2. 启动集群模式后无法连接
'以集群模式启动后无法链接的状态
需要在bin下运行mongo.exe进入设置集群'
# 如果本身就是集群模式中的节点,需要使用删除或者添加节点的方式修复。不能直接config。
# 配置config多种模式(以下都可):
1. 搭建1主1从1投票者等.
2 搭建1主多从.
3. 搭建1主2从.
4. 搭建1主1从.
5. 搭建1主.
6. 搭建其他集群节点.
1.)arbiter节点:主要负责选主过程中的投票,但是不存储任何数据,也不提供任何服务.
2.)hidden节点:隐藏节点,不参与选主,也不对外提供服务。
3.)delay节点:延时节点,数据落后于主库一段时间,因为数据是延时的,也不应该提供服务或参与选主,所以通常会配合hidden(隐藏)
config = {
_id : "dba",
members : [
{_id:0, host:"10.0.0.93:28017"},
{_id:1, host:"10.0.0.93:28018"},
{_id:2, host:"10.0.0.93:28019","arbiterOnly":true},
]
}
# 开始副本集配置
rs.initiate(config)
- 3. 节点无法链接错误
方案:修改错误的节点设置即可
# 修改副本集配置或者再次执行上一步正确配置config
例如:config={_id:"dba", members:[{_id:0, host:"10.0.0.6:111"}]}
或修改:
cfg=rs.conf() #定义变量cfg(名称任意)
cfg.members[2].priority=0 #调用变量cfg下的members.priority
#定义权重0,不参与选主
cfg.members[2].hidden=true #隐藏节点
cfg.members[2].slaveDelay=120 #延时120秒
# 增加减少查看节点
rs.add("10.0.0.8:27017")
rs.addArb("10.0.0.93:28015") #添加仲裁节点
rs.remove("10.0.0.8:27017")
rs.status()
# 查看配置文件
rs.config()
4. mongodb集群优点
- 可以生产在线同步,自动同步,随时增减节点
二、副本集的搭建
0.介绍副本集
#官网的图片
https://docs.mongodb.com/manual/replication/
#自带互相监控投票机制(分布式一致性协议Raft协议),使用了oplog.
1.创建多实例目录
[root@redis03 ~]# mkdir /server/mongodb/2701{7,8,9}/{conf,logs,pid,data} -p
2.编辑多实例配置文件
[root@redis03 ~]# vim /server/mongodb/27017/conf/mongo.conf
systemLog:
destination: file
logAppend: true
path: /server/mongodb/27017/logs/mongodb.log
#path: /server/mongodb/27018/logs/mongodb.log
#path: /server/mongodb/27019/logs/mongodb.log
storage:
journal:
enabled: true
dbPath: /server/mongodb/27017/data
#dbPath: /server/mongodb/27018/data
#dbPath: /server/mongodb/27019/data
directoryPerDB: true
wiredTiger:
engineConfig:
cacheSizeGB: 1
directoryForIndexes: true
collectionConfig:
blockCompressor: zlib
indexConfig:
prefixCompression: true
processManagement:
fork: true
pidFilePath: /server/mongodb/27017/pid/mongod.pid
#pidFilePath: /server/mongodb/27018/pid/mongod.pid
#pidFilePath: /server/mongodb/27019/pid/mongod.pid
net:
port: 27017
#port: 27018
#port: 27019
bindIp: 127.0.0.1,10.0.0.6
=========以下不用配置,会在复制集设置成功后自动生成========
replication:
#类似于binlog,指定大小
oplogSizeMB: 1024
#副本集的名称,集群名称
replSetName: dba
3.启动多实例
- 注意某些版本后需要启动时指定(--replSet 名称)的副本集模式.
[root@redis03 ~]# chown -R mongo.mongo /server/mongodb/
[root@redis03 ~]# su - mongo
[mongo@redis03 ~]mongod -f /server/mongodb/27017/conf/mongo.conf --replSet dba
[mongo@redis03 ~] mongod -f /server/mongodb/27018/conf/mongo.conf --replSet dba
[mongo@redis03 ~]mongod -f /server/mongodb/27019/conf/mongo.conf --replSet dba
#验证
[mongo@redis03 ~] netstat -lntp
tcp 0 0 10.0.0.93:27017 0.0.0.0:* LISTEN 32893/mongod
tcp 0 0 127.0.0.1:27017 0.0.0.0:* LISTEN 32893/mongod
tcp 0 0 10.0.0.93:27018 0.0.0.0:* LISTEN 32938/mongod
tcp 0 0 127.0.0.1:27018 0.0.0.0:* LISTEN 32938/mongod
tcp 0 0 10.0.0.93:27019 0.0.0.0:* LISTEN 32981/mongod
tcp 0 0 127.0.0.1:27019 0.0.0.0:* LISTEN 32981/mongod
4.登录多实例
# 只用登录主副本集设置即可.(两从库不用设置,会自动读取.)
[mongo@redis03 ~]mongo 10.0.0.6:27017
[mongo@redis03 ~] mongo 10.0.0.6:27018
[mongo@redis03 ~]$ mongo 10.0.0.6:27019
5.初始化配置副本集
# 1.配置副本集搭建1主2从
在主库上执行命令:
config = {
_id : "dba",
members : [
{_id:0, host:"10.0.0.6:27017"},
{_id:1, host:"10.0.0.6:27018"},
{_id:2, host:"10.0.0.6:27019"}
]
}
# 2.然后读取副本集config设置即可
rs.initiate(config)
- 架构1:1主2从
#配置副本集搭建1主1从1投票者.
config = {
_id : "dba",
members : [
{_id:0, host:"10.0.0.93:28017"},
{_id:1, host:"10.0.0.93:28018"},
{_id:2, host:"10.0.0.93:28019","arbiterOnly":true},
]
}
#读取副本集
rs.initiate(config)
- 架构1:1主1从1投票者
6.查看副本集状态
# 搭建成功后默认的命令提示符也会对应变更(primary).
dba:PRIMARY> rs.status()
#健康状态 1表示正常 0表示故障
"health" : 1,
#表示状态 1是主库 2是从库 3表示恢复数据中 7表示投票者 8表示down机
"state" : 1,
#标注是主库还是从库
"stateStr" : "PRIMARY",
#集群启动时间
"uptime" : 579,
#另一种格式的时间
"optime" : {
"ts" : Timestamp(1590593779, 1),
"t" : NumberLong(1)
},
#上一次心跳传过来数据的时间
"optimeDate" : ISODate("2020-05-27T15:36:19Z"),
#检测上一次心跳时间
"lastHeartbeat" : ISODate("2020-05-27T15:36:25.815Z"),
#查看集群与主节点
dba:PRIMARY> rs.isMaster()
#oplog信息
dba:PRIMARY> rs.printReplicationInfo()
configured oplog size: 1024MB
log length start to end: 1543secs (0.43hrs)
oplog first event time: Wed May 27 2020 23:26:46 GMT+0800 (CST)
oplog last event time: Wed May 27 2020 23:52:29 GMT+0800 (CST)
now: Wed May 27 2020 23:52:38 GMT+0800 (CST)
#查看延时从库信息
dba:PRIMARY> rs.printSlaveReplicationInfo()
source: 10.0.0.93:28018
syncedTo: Wed May 27 2020 23:54:19 GMT+0800 (CST)
0 secs (0 hrs) behind the primary
source: 10.0.0.93:28019
syncedTo: Wed May 27 2020 23:54:19 GMT+0800 (CST)
0 secs (0 hrs) behind the primary
#打印副本集配置文件
dba:PRIMARY> rs.config()
7.主库创建数据,从库查看数据
# 远程链接报错提示:
Warning: listdatabases failed
Hint: If this user has access to a specific database, please use "Manually specify visible databases" option in Connection Settings window -> Authentication tab.
'原因:已配置主从,但数据库主从节点有故障。'
'解决:在配置文件中取消主从配置即可。'
#主库插入数据
db.table.insertMany([{"name":"gcc","age":10},{"name":"zzy","age":9},{"name":"hxh","age":11}])
#主库查看数据
dba:PRIMARY> show tables
table
dba:PRIMARY> db.table.find()
#从库查看数据
dba:SECONDARY> show databases
2020-05-27T23:43:40.020+0800 E QUERY [thread1] Error: listDatabases failed:{
"operationTime" : Timestamp(1590594219, 1),
"ok" : 0,
"errmsg" : "not master and slaveOk=false",
"code" : 13435,
"codeName" : "NotMasterNoSlaveOk",
"$clusterTime" : {
"clusterTime" : Timestamp(1590594219, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
#连查看库都会被拒绝,因为从库不提供读写
#执行命令(从库都要执行)
dba:SECONDARY> rs.slaveOk()
dba:SECONDARY> show databases
admin 0.000GB
cluster 0.000GB
config 0.000GB
local 0.000GB
#每次重新连接都要执行以上命令才能读取
#可以配置永久生效
[root@redis03 ~]# vim ~/.mongorc.js
rs.slaveOk()
# 新版本已经默认开始支持从库读操作。
8. 延时从库的搭建
# 特殊节点介绍:
arbiter节点:主要负责选主过程中的投票,但是不存储任何数据,也不提供任何服务.
hidden节点:隐藏节点,不参与选主,也不对外提供服务。
delay节点:延时节点,数据落后于主库一段时间,因为数据是延时的,也不应该提供服务或参与选主,所以通常会配合hidden(隐藏)
# 一般情况下会将delay+hidden一起配置使用
配置延时节点(一般延时节点也配置成hidden)
------------------
cfg=rs.conf() #定义变量cfg(名称任意)
cfg.members[2].priority=0 #调用变量cfg下的members.priority定义权重0,不参与选主
cfg.members[2].hidden=true #隐藏节点
cfg.members[2].slaveDelay=120 #延时120秒
cfg.members[2].votes=0 #持有票数0
rs.reconfig(cfg) #重新加载配置永久生效
配置成功后,通过以下命令查询配置后的属性:
rs.conf();
# 取消延时节点配置
cfg=rs.conf()
cfg.members[2].priority=1
cfg.members[2].hidden=false
cfg.members[2].slaveDelay=0
cfg.members[2].votes=1
rs.reconfig(cfg)
## !! 特别注意,此处的members[2]中的2代表第三个节点,和默认的id号不同(id号可能有跳空.).
二、副本集实现高可用
1.故障切换测试
#主库使用 localhost 连接,执行关闭数据库的操作(使用ip连接是不能执行的)
mongod -f /server/mongodb/28018/conf/mongo.conf --shutdown
#查看其他从库中会有一台从库,变成主库
#故障转移实现了,但是我的程序连接mongodb的配置还需要修改怎么办??
2.程序怎么实现连接切换的
1.如果使用的是单节点,那么程序里面直接配置写死mongodb的ip和端口即可
2.如果是副本集集群的形式,在程序里面写的就是一个列表,列表里面写
mongo_reip=[10.0.0.91:28017,10.0.0.92:28018,10.0.0.93:29019]
程序会去使用命令询问谁是主节点,得到结果后在写入数据
3.恢复主库
#重新启动主库,他会自动判断谁是主库,自动成为新的从库
#注意:三台节点,只能坏一台,坏两台就有问题了
4.指定节点提升优先级
#原来的主库配置高,性能好,想恢复之后还让他是主库怎么办
#查看优先级
dba:PRIMARY> rs.conf()
#权重值
"priority" : 1,
#临时修改配置文件
dba:PRIMARY> config=rs.conf()
#修改配置文件中 id 为0 的priority值为10
dba:PRIMARY> config.members[0].priority=10
#配置文件生效
dba:PRIMARY> rs.reconfig(config)
#新版本调整完直接切换主库,旧版本需要主动降级
dba:PRIMARY> rs.stepDown()
#恢复权重
dba:PRIMARY> config=rs.conf()
dba:PRIMARY> config.members[0].priority=1
dba:PRIMARY> rs.reconfig(config)
三、扩容与删减节点
1.配置一台新的节点
#创建目录
[root@redis03 ~]# mkdir /server/mongodb/28016/{conf,logs,pid,data} -p
#配置新节点
[root@redis03 ~]# cp /server/mongodb/28017/conf/mongo.conf /server/mongodb/28016/conf/
[root@redis03 ~]# sed -i 's#28017#28016#g' /server/mongodb/28016/conf/mongo.conf
#启动新节点
[root@redis03 ~]# chown -R mongo.mongo /server/mongodb/
[root@redis03 ~]# su - mongo
[mongo@redis03 ~]$ mongod -f /server/mongodb/28016/conf/mongo.conf
2.将新节点加入集群
#主库操作
dba:PRIMARY> rs.add("10.0.0.93:28016")
{
"ok" : 1,
"operationTime" : Timestamp(1590597530, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1590597530, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
#查看集群状态
dba:PRIMARY> rs.status()
#注意:四个节点也不能坏两台机器
3.删除节点
#主库操作
dba:PRIMARY> rs.remove("10.0.0.93:28016")
{
"ok" : 1,
"operationTime" : Timestamp(1590597842, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1590597842, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
#查看集群状态
dba:PRIMARY> rs.status()
4.添加仲裁节点
#创建目录
[root@redis03 ~]# mkdir /server/mongodb/28015/{conf,logs,pid,data} -p
#配置新节点
[root@redis03 ~]# cp /server/mongodb/28017/conf/mongo.conf /server/mongodb/28015/conf/
[root@redis03 ~]# sed -i 's#28017#28015#g' /server/mongodb/28015/conf/mongo.conf
#启动新节点
[root@redis03 ~]# chown -R mongo.mongo /server/mongodb/
[root@redis03 ~]# su - mongo
[mongo@redis03 ~]$ mongod -f /server/mongodb/28015/conf/mongo.conf
#主库操作加入仲裁节点
dba:PRIMARY> rs.addArb(("10.0.0.93:28015")
#查看该库是否有数据
#注意,五个节点时,可以坏两个节点