复制集注意事项
关于复制集:
- 复制集为 MongoDB 提供了数据可靠性,当某个节点挂掉,可以重新选举出主节点;
- 复制集为 MongoDB 提供了数据安全性,当节点宕机后,备份数据保证数据不丢失;
- 复制集为 MOngoDB 提供了高性能,可通过配置主从读写分离提高服务性能;
关于硬件:
- 因为正常的复制集节点都有可能成为主节点,它们的地位是一样的,因此硬件配置上必须一致;
- 为了保证节点不会同时宕机,各节点使用的硬件必须具有独立性;
- 此处用的 Docker 在同一个虚拟机上模拟三个节点;
关于软件:
- 复制集各节点软件版本必须一致,以避免出现不可预知的问题;
- 增加节点不会增加系统写性能;
- 此处用的 MongoDB 6.0.5 版本;
环境准备
- Docker 安装 MongoDB 并配置好环境变量;
- 确保有 10GB 以上的硬盘空间;
- 默认已安装 Docker,没安装的话请参考我的 Docker 教程;
- 宿主机器为 CentOS7;
一主两从架构图:
安装步骤
(1)准备配置文件
复制集的每个 mongod 进程应该位于不同的服务器。我们现在在一台机器上运行 3 个进程,因此要为它们各自配置:
- 不同的端口(28017/28018/28019)
- 不同的数据目录
bash
mkdir -p /data/db{1,2,3}
- 不同日志文件路径(例如:/data/db1/logs)
java
mkdir -p /data/db{1,2,3}/logs
创建配置文件/data/db1/mongod.conf
,内容如下:
bash
systemLog:
destination: file
path: /data/logs/mongod.log # log path
logAppend: true
storage:
dbPath: /data/db # data directory
net:
bindIp: 0.0.0.0
port: 27017 # port
replication:
replSetName: rs0 # 复制集名称
# processManagement: # 设置了该项会导致docker exec -it mongodb1 bash 进入容器后马上自动退出
# fork: true
将该配置文件复制都 db2、db3 对应的目录下,注意其中配置的是容器中的地址,而不是宿主机对应的地址,且必须是 yaml 格式。
(2)启动 docker
启动第 1 个 mongod:
bash
docker run --name mongodb1 -d --restart=always -v /data/db1:/data/db -v /data/db1/logs:/data/logs -v /data/db1/mongod.conf:/data/conf/mongod.conf -p 28017:27017 mongo:6.0.5 --config /data/conf/mongod.conf
--name:指定容器名称
-d:后台运行
--restart:设置容器的重启策略,always 表示重启宿主机自动运行 docker
-v:将宿主机文件挂载到容器中,注意格式为:"宿主机路径 : 容器路径"
-p:绑定宿主机和容器的端口,注意格式为:"宿主机端口 : 容器端口"
mongo:6.0.5:指定镜像名和版本号
--config:指定启动的配置文件,容器中的路径
启动第 2 个 mongod:
bash
docker run --name mongodb2 -d --restart=always -v /data/db2:/data/db -v /data/db2/logs:/data/logs -v /data/db2/mongod.conf:/data/conf/mongod.conf -p 28018:27017 mongo:6.0.5 --config /data/conf/mongod.conf
启动第 3 个 mongod:
bash
docker run --name mongodb3 -d --restart=always -v /data/db3:/data/db -v /data/db3/logs:/data/logs -v /data/db3/mongod.conf:/data/conf/mongod.conf -p 28019:27017 mongo:6.0.5 --config /data/conf/mongod.conf
查看 docker 进程状态及网络端口:
注意 docker 启动,宿主机的防火墙 firewalld 必须开启,否则会报如下错误:
通过客户端工具访问 mongodb:
进入 docker 容器操作 mongodb:
bash
# 宿主机进入容器
docker exec -it mongodb1 bash
# 进入容器mongodb的命令行模式
mongosh
# 查看mongodb数据库
show dbs
至此,三个 mongod 节点安装完成。
配置复制集
复制集通过 mongosh 的 rs.initiate()
进行初始化,初始化后各个成员间开始发送心跳消息,并发起 Priamry 选举操作,获得大多数成员投票支持的节点,会成为 Primary,其余节点成为 Secondary。
进入 mongdb1 节点后执行 mongosh 命令后:
bash
# mongosh --port 28017
# 初始化复制集
> rs.initiate({
_id: "rs0",
members: [{
_id: 0,
host: "192.168.10.101:28017"
},{
_id: 1,
host: "192.168.10.101:28018"
},{
_id: 2,
host: "192.168.10.101:28019"
}]
})
提示{ok:1}表示初始化成功:
验证主从节点读写操作:
- MongoDB 主节点进行写入
bash
# mongosh --port 28017
rs0 [direct: primary] test> db.user.insertMany([{name:"firechou"},{name:"monkey"}])
- 切换到从节点写入,抛出异常
MongoBulkWriteError: not primary
bash
# mongosh --port 28018
rs0 [direct: secondary] test> db.user.insertMany([{name:"firechou"},{name:"monkey"}])
- MongoDB 从节点进行读
bash
# mongosh --port 28018
# 指定从节点可读
rs0:SECONDARY> rs.secondaryOk() # 需要执行该命令,否则会报错
rs0:SECONDARY> db.user.find()
或者执行如下命令开启从节点读:
bash
db.getMongo().setReadPref("secondary")
- 模拟重新选举 Master
停掉 mongodb1 服务:
查看 mongodb2 服务已被选举成了 Primary 节点:
启动 mongodb1 后再次执行写入操作,提示非主节点不能写入:
复制集状态查询
- 查看复制集整体状态:
bash
rs.status()
可查看各成员当前状态,包括是否健康,是否在全量同步,心跳信息,增量同步信息,选举信息,上一次的心跳时间等。
说明:
members:数组,一列体现了所有复制集成员的状态,主要如下:
health:成员是否健康,通过心跳进行检测。
state/stateStr:成员的状态,PRIMARY 表示主节点,而 SECONDARY 则表示备节点,如果节点出现故障,则可能出现一些其他的状态,例如 RECOVERY。
uptime:成员的启动时间。
optime/optimeDate:成员同步最后一条 oplog 的时间。
optimeDurable/optimeDurableDate:成员同步最后一条 oplog 持久化的时间。
pingMs:成员与当前节点的 ping 时延。
syncingTo:成员的同步来源。
- 查看当前节点角色:
bash
db.isMaster()
除了当前节点角色信息,是一个更精简化的信息,也返回整个复制集的成员列表,真正的 Primary 是谁,协议相关的配置信息等,Driver 在首次连接复制集时会发送该命令。
Mongos 复制集常用命令
**命令 ** | 描述 |
---|---|
rs.add() | 为复制集新增节点 |
rs.addArb() | 为复制集新增一个 arbiter |
rs.conf() | 返回复制集配置信息 |
rs.freeze() | 防止当前节点在一段时间内选举成为主节点 |
rs.help() | 返回 replica set 的命令帮助 |
rs.initiate() | 初始化一个新的复制集 |
rs.printReplicationInfo() | 以主节点的视角返回复制的状态报告 |
rs.printSecondaryReplicationInfo() | 以从节点的视角返回复制状态报告 |
rs.reconfig() | 通过重新应用复制集配置来为复制集更新配置 |
rs.remove() | 从复制集中移除一个节点 |
rs.secondaryOk() | 为当前的连接设置从节点可读 |
db.getMongo().setReadPref("secondary") | 为当前的连接设置从节点可读,推荐使用 |
rs.status() | 返回复制集状态信息 |
rs.stepDown() | 让当前的 primary 变为从节点并触发 |
electionrs.syncFrom() | 设置复制集节点从哪个节点处同步数据,将会覆盖默认选取逻辑 |