MongoDB复制集
MongoDB复制集概述
复制集(Replica Sets)是额外的数据副本,是跨多个服务器同步数据的过程,复制集提供了冗余并增加了数据可用性,通过复制集可以对硬件故障和中断的服务进行恢复
复制集的优势:
- 让数据更安全
- 数据高可用性
- 灾难恢复
- 无停机维护(备份、索引重建、故障转移)
- 读缩放(额外的副本读取)
- 副本集对应用程序是透明的
复制集工作原理
MongoDB的复制集至少需要两个节点。其中一个是主节点(Primary),负责处理客户端的请求,其余的都是从节点(Secondary),负责复制主节点上的数据。
- 主节点记录所有变化到oplog日志,从节点复制主节点的oplog并将这些日志在从节点重做,各个节点之间会定期发送心跳信息,一旦主机宕机,则触发选举出一个新的主节点,剩余从节点指向新的主节点
- 集群存活节点小于等于二分之一时集群不可写,只可读,是否能选举出新的主节点,是由当前复制集成员存活数量来决定的
- 三类节点
- 标准(host)节点:存储数据,可能被选为活跃(primary)节点,有选举权
- 被动(passive)节点:被动节点有完整副本,不可能成为活跃节点,有选举权
- 仲裁(arbiter)节点:负责选举,不存储数据,不能充当主从节点
复制集特点:
- N个节点的集群
- 任何节点可作为主节点
- 所有写入操作都在主节点上
- 自动故障转移
- 自动恢复
MongoDB复制集部署
配置复制集
准备工作 创建数据文件和日志文件存储路径
并且更改不同实例的配置文件
因为工作重复度高 因此写一个脚本
#!/bin/bash
CONF=/usr/local/mongodb/bin
DATA=/data
LOGS=/data/logs/mongodb
NUM1=27017
echo 'export PATH=$PATH:/usr/local/mongodb/bin' >> /etc/profile
source /etc/profile
mkdir -p $DATA &>/dev/null
mkdir -p $LOGS &>/dev/null
menu() {
cat <<-EOF
#########################
# 1.创建实例 #
# 2.开启所有实例 #
# 3.关闭所有实例 #
#########################
EOF
}
menu
read -p '想创建几个实例:' NUM2
read -p '请输入Mongodb服务器的ip地址:' IP
NUM=$[ $NUM1 + $NUM2 ]
for ((i=$NUM1;i<$NUM;i++))
do
mkdir -p $DATA/mongodb-$i
touch $LOGS/mongodb-$i.log
chmod -R 777 $LOGS/mongodb-$i.log
cat /etc/mongod.conf |grep -v '^#' |grep -v '^$' > $CONF/mongod-$i.conf
sleep 1
sed -ri "/path/c \ path: $LOGS/mongodb-$i.log" $CONF/mongod-$i.conf &>/dev/null
sed -ri "/dbPath/c \ dbPath: $DATA/mongodb-$i" $CONF/mongod-$i.conf &>/dev/null
sed -ri "/port:/c \ port: $i" $CONF/mongod-$i.conf &>/dev/null
sed -ri "/bindIp:/c \ bindIp: $IP" $CONF/mongod-$i.conf &>/dev/null
done
}
kai() {
read -p '开启几个实例:' NUM2
NUM=$[ $NUM1 + $NUM2 ]
for ((i=$NUM1;i<=$NUM;i++))
do
mongod -f $CONF/mongod-$i.conf
done
ss -ntl
}
guan() {
read -p '关闭几个实例:' NUM2
NUM=$[ $NUM1 + $NUM2 ]
for ((i=$NUM1;i<=$NUM;i++))
do
mongod -f $CONF/mongod-$i.conf --shutdown
done
ss -ntl
}
while :
do
read -p '请输入你想执行的功能(h返回菜单,q退出):' action
case $action in
1)
shili
;;
2)
kai
;;
3)
guan
;;
h)
menu
;;
q)
break
;;
*)
echo '请选择正确选项!'
esac
done
在四个节点的配置文件里添加
replication:
oplogSizeMB: 2048 带宽
replSetName: maomao 复制集的名字
进入主节点进行复制集的配置
重启mongod之后 进入
mongo --host 192.168.188.101 --port 27017
> show dbs; # 报错:说明复制集还未配置
2021-04-20T01:56:01.317-0400 E QUERY [thread1] Error: listDatabases failed:{
"ok" : 0,
"errmsg" : "not master and slaveOk=false",
"code" : 13435,
"codeName" : "NotMasterNoSlaveOk"
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:62:1
shellHelper.show@src/mongo/shell/utils.js:814:19
shellHelper@src/mongo/shell/utils.js:704:15
@(shellhelp2):1:1
查看复制集的状态
> rs.status()
{
"info" : "run rs.initiate(...) if not yet done for the set",
"ok" : 0,
"errmsg" : "no replset config has been received",
"code" : 94,
"codeName" : "NotYetInitialized"
}
配置复制集
config={_id:"maomao",members[
{_id:0,host:"192.168.188.101:27017"},
{_id:1,host:"192.168.188.101:27018"},
{_id:2,host:"192.168.188.101:27019"}]}
{
"_id" : "maomao",
"members" : [
{
"_id" : 0,
"host" : "192.168.188.101:27017"
},
{
"_id" : 1,
"host" : "192.168.188.101:27018"
},
{
"_id" : 2,
"host" : "192.168.188.101:27019"
}
]
}
初始化复制集
注意:初始化之前 必须清空所有的数据库 不然会失败
删除对应的Mongodb文件数据目录里面的所有东西就行了
rs.initiate(config)
{ "ok" : 1 }
验证
初始化完成后的服务器会拥有other状态,这代表着他们正在进行投票
maomao:OTHER>
当投票完成后,默认会选举初始化的这台数据库变为主库
maomao:PRIMARY>
另外两个节点
mongo --host 192.168.188.101 --port 27018
maomao:SECONDARY>
再次通过rs.status()查看复制集完整信息
maomao:PRIMARY> rs.status()
其中health 1为健康,0代表宕机
state为1 表示主节点,2为从节点
...
"_id" : 1,
"name" : "192.168.188.101:27018",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
...
增加和删除节点
配置启动复制集后,还可以通过rs.add()
和rs.remove()
命令方便地添加或删除节点
maomao:PRIMARY> rs.remove("192.168.188.101:27020")
{ "ok" : 1 }
maomao:PRIMARY> rs.status()
可以查看到新添加节点的信息
maomao:PRIMARY> rs.remove("192.168.188.101:27020")
{ "ok" : 1 }
MongoDB 复制集切换
MongoDB 复制集可以实现集群的高可用,当其中主节点出现故障时,会自动切换到其他节点。管理员也可以手动进行复制集的主从切换
故障自动切换
我们将主节点关闭
[root@mongodb bin]# mongod -f mongod-27017.conf --shutdown
killing process with pid: 3097
[root@mongodb bin]# ss -ntl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 192.168.188.101:27018 *:*
LISTEN 0 128 192.168.188.101:27019 *:*
LISTEN 0 128 192.168.188.101:27020 *:*
发现20718节点成为主节点
查看状态
maomao:PRIMARY> rs.status()
可以发现原"_id"为0的主节点出现故障之后,主节点自动切换到"_id"为1的节点上了
然后将之前的主节点恢复 结果发现旧的主节点成为了从节点
[root@mongodb bin]# mongod -f mongod-27017.conf
maomao:SECONDARY>
手动主从切换
原理是进入到主数据库使得数据库进行短暂的休眠,并且主动交出主节点位置
暂停30s不参加竞选
maomao:PRIMARY> rs.freeze(30)
{
"ok" : 0,
"errmsg" : "cannot freeze node when primary or running for election. state: Primary",
"code" : 95,
"codeName" : "NotSecondary"
}
交出主节点位置,维持从节点状态不少于60s,同时等待30s,使主节点和从节点日志同步
maomao:PRIMARY> rs.stepDown(60,30)
2021-04-20T02:38:16.098-0400 E QUERY [thread1] Error: error doing query: failed: network error while att
empting to run command 'replSetStepDown' on host '192.168.188.101:27018' :DB.prototype.runCommand@src/mongo/shell/db.js:132:1
DB.prototype.adminCommand@src/mongo/shell/db.js:150:16
rs.stepDown@src/mongo/shell/utils.js:1351:12
@(shell):1:1
2021-04-20T02:38:16.101-0400 I NETWORK [thread1] trying reconnect to 192.168.188.101:27018 (192.168.188.10
1) failed2021-04-20T02:38:16.101-0400 I NETWORK [thread1] reconnect 192.168.188.101:27018 (192.168.188.101) ok
然后发现27018成为了从节点
maomao:SECONDARY>
27019成为了主节点
maomao:SECONDARY>
maomao:PRIMARY>
MongoDB 复制选举原理
MongoDB在副本集中,会自动进行主节点的选举,主节点选举的触发条件:
- 主节点故障
- 主节点网络不可达(默认心跳信息为10秒)
- 人工干预(rs.stepDown(600))
一旦触发选举,就要根据一定规则来选主节点。
选举规则是根据票数来决定谁获胜:
-
票数最高,且获得了“大多数”成员的投票支持的节点获胜
- “大多数”的定义为:假设复制集内投票成员数量为N,则大多数为 N/2 + 1。例如:3个投票成员,
则大多数的值是2。当复制集内存活成员数量不足大多数时,整个复制集将无法选举出Primary,
复制集将无法提供写服务,处于只读状态。
- “大多数”的定义为:假设复制集内投票成员数量为N,则大多数为 N/2 + 1。例如:3个投票成员,
-
若票数相同,且都获得了“大多数”成员的投票支持的,数据新的节点获胜
-
数据的新旧是通过操作日志oplog来对比的。
在获得票数的时候,优先级(priority)参数影响重大
可以通过设置优先级(priority)来设置额外票数。优先级即权重,取值为0-1000,相当于可额外增加
0-1000的票数,优先级的值越大,就越可能获得多数成员的投票(votes)数。指定较高的值可使成员更有资格成为主要成员,更低的值可使成员更不符合条件
默认情况下,优先级的值是1
查看oplog日志
maomao:PRIMARY> db.oplog.rs.find()
其中每个文档都代表主节点上执行的一个操作,oplog会包含所有对数据有修改的操作(查询操作不会记录)
配置复制集的优先级
- 三类节点
- 标准(host)节点:存储数据,只有标准节点才可能被选为活跃(primary)节点,有选举权
- 被动(passive)节点:被动节点有完整副本,不可能成为活跃节点,有选举权
- 仲裁(arbiter)节点:负责选举,不存储数据,不能充当主从节点
重新配置4个节点的MongoDB 复制集,设置两个标准节点,一个被动节点和一个仲裁节点
maomao:PRIMARY> config={_id:"maomao",members:[{_id:0,host:"192.168.188.101:27017",priority:0},{_id:1,host:"
192.168.188.101:27018",priority:100},{_id:2,host:"192.168.188.101:27019",priority:100},{_id:3,host:"192.168.188.101:27020",arbiterOnly:true}]}
{
"_id" : "maomao",
"members" : [
{
"_id" : 0,
"host" : "192.168.188.101:27017",
"priority" : 0
},
{
"_id" : 1,
"host" : "192.168.188.101:27018",
"priority" : 100
},
{
"_id" : 2,
"host" : "192.168.188.101:27019",
"priority" : 100
},
{
"_id" : 3,
"host" : "192.168.188.101:27020",
"arbiterOnly" : true
}
]
}
激活
maomao:PRIMARY> rs.reconfig(config)
{ "ok" : 1 }
查看节点信息
maomao:PRIMARY> rs.isMaster()
{
"hosts" : [
"192.168.188.101:27018",
"192.168.188.101:27019"
],
"passives" : [
"192.168.188.101:27017"
],
"arbiters" : [
"192.168.188.101:27020"
],
其中hosts 包含标准节点
passives 包含被动节点
arbiters 包含仲裁节点
模拟主节点故障
主节点故障 另一个标准节点将会成为新的主节点
mongod -f /usr/local/mongodb/bin/mongod-27019.conf --shutdown
maomao:PRIMARY> rs.status()
查看信息
当主节点为第一个标准节点出现故障后,MongoDB复制集会选举第二个标准节点为主节点
如果所有标准节点都故障,被动节点也不能成为主节点
MongoDB 复制集管理
配置允许在从节点读取数据
默认MongoDB 复制集的从节点不能读取数据,可以使用rs.slaveOk()
命令允许能够在从节点读取数据
进入从节点
mongo --host 192.168.188.101 --port 27017
这时候无法读取数据
maomao:SECONDARY> show dbs
2021-04-20T03:09:14.589-0400 E QUERY [thread1] Error: listDatabases failed:{
"ok" : 0,
"errmsg" : "not master and slaveOk=false",
"code" : 13435,
"codeName" : "NotMasterNoSlaveOk"
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:62:1
shellHelper.show@src/mongo/shell/utils.js:814:19
shellHelper@src/mongo/shell/utils.js:704:15
@(shellhelp2):1:1
允许能够在从节点读取数据
maomao:SECONDARY> rs.slaveOk()
maomao:SECONDARY> show dbs
admin 0.000GB
local 0.000GB
查看复制状态信息
可以使用rs.printReplicationInfo()
和rs.printSlaveReplicationInfo()
命令来查看复制集状态
maomao:SECONDARY> rs.printReplicationInfo()
configured oplog size: 2048MB
log length start to end: 3597secs (1hrs)
oplog first event time: Tue Apr 20 2021 02:11:44 GMT-0400 (EDT)
oplog last event time: Tue Apr 20 2021 03:11:41 GMT-0400 (EDT)
now: Tue Apr 20 2021 03:11:43 GMT-0400 (EDT)
maomao:SECONDARY> rs.printSlaveReplicationInfo()
source: 192.168.188.101:27017
syncedTo: Tue Apr 20 2021 03:12:01 GMT-0400 (EDT)
0 secs (0 hrs) behind the primary
source: 192.168.188.101:27019
syncedTo: Tue Apr 20 2021 03:12:01 GMT-0400 (EDT)
0 secs (0 hrs) behind the primary
更改oplog大小
-
oplog默认占用实例5%大小,复制过程中,如果oplog不够大,因为同步时间差,可能导致从节点跟不上主节点。因此需要保证主节点oplog足够大
-
更改命令:
db.runCommand({"convertToCapped":"oplog.rs","size":102400000})
maomao:PRIMARY> use local
switched to db local
maomao:PRIMARY> db.oplog.rs.stats()
{
"ns" : "local.oplog.rs",
"size" : 35566,
"count" : 370,
"avgObjSize" : 96,
"storageSize" : 49152,
maomao:PRIMARY> rs.printReplicationInfo()
configured oplog size: 2048MB
log length start to end: 3847secs (1.07hrs)
oplog first event time: Tue Apr 20 2021 02:11:44 GMT-0400 (EDT)
oplog last event time: Tue Apr 20 2021 03:15:51 GMT-0400 (EDT)
now: Tue Apr 20 2021 03:15:55 GMT-0400 (EDT)
maomao:PRIMARY> db.runCommand({"convertToCapped":"oplog.rs","size":102400000})
{ "ok" : 1 }
部署认证的复制
maomao:PRIMARY> use admin
switched to db admin
maomao:PRIMARY> db.createUser({user:"root",pwd:"123",roles:["root"]})
Successfully added user: { "user" : "root", "roles" : [ "root" ] }
关闭四个节点
killing process with pid: 3492
killing process with pid: 3782
killing process with pid: 3684
killing process with pid: 3620
mkdir /data/user
生成秘钥文件
openssl rand -base64 756 > /data/user/testKeyFile.file
修改权限
chmod 400 /data/user/testKeyFile.file
cp /data/user/testKeyFile.file /data/user/testKeyFile1.file
cp /data/user/testKeyFile.file /data/user/testKeyFile2.file
cp /data/user/testKeyFile.file /data/user/testKeyFile3.file
在每个节点配置文件里添加
security:
keyFile: /data/user/testKeyFile.file
authorization: enabled
注意:每个节点testKeyFile.file 名字不一样
启动数据库
[root@mongodb ~]# mongo --host 192.168.188.101 --port 27019
MongoDB shell version v3.4.24
connecting to: mongodb://192.168.188.101:27019/
MongoDB server version: 3.4.24
不能读取数据 需要验证用户
maomao:PRIMARY> show dbs
2021-04-20T03:31:58.572-0400 E QUERY [thread1] Error: listDatabases failed:{
"ok" : 0,
"errmsg" : "not authorized on admin to execute command { listDatabases: 1.0 }",
"code" : 13,
"codeName" : "Unauthorized"
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:62:1
shellHelper.show@src/mongo/shell/utils.js:814:19
shellHelper@src/mongo/shell/utils.js:704:15
@(shellhelp2):1:1
maomao:PRIMARY> use admin
switched to db admin
maomao:PRIMARY> db.auth("root","123")
1
maomao:PRIMARY> show dbs
admin 0.000GB
local 0.000GB
认证用户成功