# MongoDB 副本集集群部署

# MongoDB 集群部署的两种方式

MongoDB 主从复制(已废弃)
MongoDB 副本集

MongoDB副本集(Replica Set)其实就是具有自动故障恢复功能的主从集群,和主从复制最大的区别就是在副本集中没有固定的“主节点”,整个副本集会选出一个节点作为“主节点”,当其挂掉后,再在剩下的从节点中选举一个节点成为新的“主节点”,在副本集中总有一个主节点(primary)和一个或多个备份节点(secondary)。

除了 primary 和 secondary 之外,副本集中的节点还可以是以下角色:

成为 primary 对客户端可见 参与投票 延迟同步 复制数据
Default
Secondary-Only
Hidden
Delayed
Arbiters
Non-Voting

关于副本集的基础概念,可以参考:https://blog.csdn.net/pengjunlee/article/details/83958794 (opens new window)

官方帮助文档:https://docs.mongodb.com/manual/replication/ (opens new window)

官方推荐的副本集最小配置需要有三个节点:一个主节点接收和处理所有的写操作,两个备份节点通过复制主节点的操作来对主节点的数据进行同步备份。

# 配置副本集

# 安装环境

  • 3 台服务器,官方推荐副本集部署至少需要 3 个节点
  • 操作系统:CentOS 7.x
  • MongoDB:4.0.x

副本集各节点 IP 如下:

192.168.202.131

192.168.202.132

192.168.202.133

# 安装 MongoDB 服务器

1、下载 MongoDB 安装包

curl -O https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-4.0.23.tgz

2、解压安装

tar -xf mongodb-linux-x86_64-4.0.23.tgz
mv mongodb-linux-x86_64-4.0.23 /usr/local/mongodb-4.0.23

3、创建数据目录、日志目录

mkdir /usr/local/mongodb-4.0.23/{data,log}

4、创建配置文件,设置副本集名称(各个节点副本集名称相同)

cat << EOF > /usr/local/mongodb-4.0.23/mongod.conf
systemLog:
  destination: file
  path: /usr/local/mongodb-4.0.23/log/mongod.log
  logAppend: true
  # 日志分割
  #logRotate: reopen
# 副本集设置
replication:
  replSetName: rs1
#  oplogSizeMB: 10240
#security:
#  authorization: enabled
#  keyFile: /usr/local/mongodb-4.0.23/keyfile
storage:
  dbPath: /usr/local/mongodb-4.0.23/data
processManagement:
  fork: true
  pidFilePath: /var/run/mongod.pid
net:
  bindIp: 0.0.0.0
  port: 27017
  maxIncomingConnections: 65535
EOF

5、设置 MongoDB 系统服务

cat << EOF > /usr/lib/systemd/system/mongodb.service
[Unit]
Description=mongodb
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
ExecStart=/usr/local/mongodb-4.0.23/bin/mongod --config /usr/local/mongodb-4.0.23/mongod.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/usr/local/mongodb-4.0.23/bin/mongod --shutdown --config /usr/local/mongodb-4.0.23/mongod.conf
PrivateTmp=true

[Install]
WantedBy=multi-user.target

EOF

6、刷新 systemctl 服务

systemctl daemon-reload

7、设置开机自启

systemctl enable mongodb

查看开机自启是否设置成功

systemctl list-unit-files | grep mongodb

8、启动 MongoDB 服务

systemctl start mongodb

9、关闭防火墙或者开放 27017 端口

[参考]:CentOS7 关闭 selinux、防火墙

至此,3 个 MongoDB 实例都已经以副本集方式启动,但它们彼此之间现在还不会进行通信,仍需要进行一些配置。

# 副本集初始化

通过 Shell 连接到任意一个 MongoDB 实例,执行 rs.initiate() 方法对副本集进行初始化。

/usr/local/mongodb-4.0.23/bin/mongo 192.168.202.131:27017
// priority 为权重,默认值是1,权重大的会被置为 Primary 节点
conf = {
  _id: "rs1",
  members: [
    { _id: 0, host: "192.168.202.131:27017", priority: 5 },
    { _id: 1, host: "192.168.202.132:27017", priority: 3 },
    { _id: 2, host: "192.168.202.133:27017", priority: 1 }
  ]
}
rs.initiate(conf)

如果在执行 rs.initiate() 方法时不传入任何参数,MongoDB 将以默认的配置文档对副本集进行初始化,后续可以再通过 rs.add() 方法来向副本集中添加成员。

# 副本集更新

// 向副本集中添加成员
rs.add("192.168.202.150:27017")
 
// 从副本集中删除成员
rs.remove("192.168.202.150:27017")
 
// 向副本集中添加仲裁
rs.addArb("192.168.202.150:27017")
 
// 向副本集中添加备份节点
rs.add({ _id: 3, host: "192.168.202.150:27017",  priority: 0, hidden: true })
# 更改副本集配置
rs1:PRIMARY> var conf = rs.conf()
rs1:PRIMARY> conf.members[1].priority = 10
 
# PRIMARY 节点上执行如下命令
rs1:PRIMARY> rs.reconfig(conf)
 
# 如果在 SECONDARY节点上执行上面的命令,需增加 force 参数
rs1:SECONDARY> rs.reconfig(conf, { force: true })

提示

强制让一个节点成为 Primary,可以将该节点的优先级设置成最高。

conf = rs.conf()
conf.members[0].priority = 5
conf.members[1].priority = 1
conf.members[2].priority = 1
rs.reconfig(conf)

# 副本集监控

1、查看副本集的配置信息

rs1:PRIMARY> rs.conf()

2、查看副本集运行状态

rs1:PRIMARY> rs.status()

3、查看备份节点的复制信息

rs1:PRIMARY> db.printSecondaryReplicationInfo()

# 副本集测试

# 复制测试

1、在 Primary 上插入 10 条客户数据:

rs1:PRIMARY> for(var i = 0; i < 10; i++) { db.customer.insert({name: "user" + i }) }

2、在 Secondary 上查看客户数据是否已经同步:

rs1:SECONDARY> rs.secondaryOk()
rs1:SECONDARY> db.customer.count()  # 10

# 故障转移测试

1、查看 Primary 节点关闭之前的状态

rs1:PRIMARY> rs.status()

2、执行如下命令关闭 Primary 节点,查看其他 2 个节点的情况

systemctl stop mongodb

3、在任意其他节点上查看 Primary 节点关闭之后的状态

rs.status()

4、再次启动 192.168.202.131:27017 节点,由于其选举优先级最高,自动被选举为 Primary

// 待 192.168.202.131:27017 节点启动后再次查看副本集状态
rs.status()

# 开启安全认证

# 创建用户

登录 PRIMARY 节点创建用户,在此我们创建以下两个用户:

  • root:超级管理员,对数据库拥有完全管理权限
  • admin:对所有数据库表有读写权限
rs1:PRIMARY> show dbs
admin   0.000GB
config  0.000GB
local   0.001GB
test    0.000GB

rs1:PRIMARY> use admin
switched to db admin

# 创建 root 用户
rs1:PRIMARY> db.createUser({ user: "root", pwd: "root123", roles: [{ role: "root", db: "admin" }] })

# 创建 admin 用户
rs1:PRIMARY> db.createUser({ user: "admin", pwd: "admin123", roles: [{ role: "readWriteAnyDatabase", db: "admin" }] })

# 创建 keyFile 文件

1、先停掉所有 SECONDARY 节点的 MongoDB 服务,然后再停掉 PRIMARY 节点的 MongoDB 服务

systemctl stop mongodb

2、在 PRIMARY 节点所在服务器上创建 keyFile 文件。

openssl rand -base64 666 > /usr/local/mongodb-4.0.23/keyfile
chmod 600 /usr/local/mongodb-4.0.23/keyfile

3、将生成的 keyFile 文件拷贝到其他节点服务器上,并修改文件的操作权限为 600

cd /usr/local/mongodb-4.0.23/
scp keyfile root@192.168.202.132:`pwd`
scp keyfile root@192.168.202.133:`pwd`

# 在另外两个节点修改 keyfile 文件权限
chmod 600 /usr/local/mongodb-4.0.23/keyfile

# 更新启动配置文件

1、修改 PRIMARY 节点的 mongodb.conf 文件,增加如下内容

replication:
  oplogSizeMB: 10240
security:
  authorization: enabled
  keyFile: /usr/local/mongodb-4.0.23/keyfile

快速修改

sed -i 's/#  oplogSizeMB/  oplogSizeMB/g' /usr/local/mongodb-4.0.23/mongod.conf && \
sed -i 's/#security/security/g' /usr/local/mongodb-4.0.23/mongod.conf && \
sed -i 's/#  authorization/  authorization/g' /usr/local/mongodb-4.0.23/mongod.conf && \
sed -i 's/#  keyFile/  keyFile/g' /usr/local/mongodb-4.0.23/mongod.conf

2、修改 SECONDARY 节点的 mongodb.conf 文件,增加如下内容

replication:
  oplogSizeMB: 10240
security:
  keyFile: /usr/local/mongodb-4.0.23/keyfile

快速修改

sed -i 's/#  oplogSizeMB/  oplogSizeMB/g' /usr/local/mongodb-4.0.23/mongod.conf && \
sed -i 's/#security/security/g' /usr/local/mongodb-4.0.23/mongod.conf && \
sed -i 's/#  keyFile/  keyFile/g' /usr/local/mongodb-4.0.23/mongod.conf

# 启动副本集

1、先以 --auth 方式启动 PRIMARY 节点

systemctl start mongodb

2、再启动 SECONDARY 节点

systemctl start mongodb

# 登录测试

/usr/local/mongodb-4.0.23/bin/mongo \
-uadmin -padmin123 \
--authenticationDatabase admin \
192.168.202.131:27017

# 日志分割

MongoDB 默认是没有进行日志分割的,所有的日志持续写到一个文件中。缺点是很明显的,日志文件会越来越大:

  • 占用过多磁盘空间
  • 日志文件写入性能越来越低
  • 问题排查越来越困难

# 配置分割策略

修改各个节点的 mongodb.conf 文件,增加如下内容

systemLog:
  logRotate: reopen

快速修改

sed -i 's/  #logRotate/  logRotate/g' /usr/local/mongodb-4.0.23/mongod.conf

# 使用 Linux/Unix 系统的 logRotate 工具分割日志

1、在 /etc/logrotate.d/ 目录下新建一个名为 mongod 的文件

cat << EOF > /etc/logrotate.d/mongod
/usr/local/mongodb-4.0.23/log/*.log {
    create 0644 root root
    # 按日切分
    daily
    # 最多保留90个
    rotate 90
    # 切分文件加日期后缀
    dateext
    # 没有就不执行
    missingok
    # 空的就不执行
    notifempty
    sharedscripts
    postrotate
        # 切分完成后, 通知 MongoDB 重开文件
        /bin/kill -USR1 \`cat /run/mongod.pid 2>/dev/null\` 2>/dev/null || true
    endscript
}
EOF

2、这个配置文件的权限必须为 -rw-r--r--,不然 logrotate 不认

chmod 644 /etc/logrotate.d/mongod

3、测试日志分割

logrotate -f /etc/logrotate.d/mongod
ls /usr/local/mongodb-4.0.23/log/

非常感谢以下文章的作者。

MongoDB之副本集配置 (opens new window)

MongoDB日志分割 (opens new window)