MongoDB搭建集群

单机版MongoDB隐患

  • 没有灾备能力:在单节点宕机的情况下,服务不可用会拖垮整个系统;

  • 吞吐量不够:系统并发较高、访问量过大时,单节点无法承载流量;

  • 拓展性不足:只能通过升级单节点的硬件配置,无法横向拓展;

  • 数据安全风险:在极端情况下,数据损坏或出现丢失,无法有效恢复。

副本集群介绍

MongoDB副本集群,也被称之为复制集群,内在含义是:一个主节点拥有读写能力,一或多个从节点全量拷贝主节点的数据,对外提供读的能力

MongoDB副本集群,在主节点发生故障的情况下,无需任何外力介入,能自动完成主从切换,从而对外实现真正意义上的7*24h高可用,并且从节点还可以处理读请求,从而保障MongoDB服务的高性能。

MongoDB三个节点角色

  1. Primary主节点:拥有读写能力,为集群内的副本节点,提供数据拷贝的支持;

  2. Replicate副本节点:拥有读能力,数据完全拷贝自主节点,即主从概念中的从节点;

  3. Arbiter仲裁节点:不具备读写能力,用于故障恢复,提供故障检测、选举投票能力。

仲裁节点:作用等同于哨兵节点,但它并不是副本集群必须存在的节点,因为主节点、副本节点都拥有投票能力,它的存在只是为了维护集群内的平衡,如集群节点为偶数时,可以添加一个仲裁节点,让集群保持奇数特性,确保每轮选举一次就能推出新主,避免多轮无效竞选的现象出现


集群搭建

机器准备(已设置环境变量)

主机名

IP地址

MongoDB-1(仲裁)

192.168.7.100

MongoDB-2(主)

192.168.7.101

MongoDB-3(从)

192.168.7.102

集群模式

  • 单机模式:一台机器对外提供服务;

  • 集群模式:多台机器对外提供同一服务;

  • 伪集群模式:单台机器上启动多个实例,模拟多机器场景对外提供服务。

集群搭建

编写主节点的配置文件

 # ============================================================
 # MongoDB 副本集配置文件 - 主节点(PRIMARY)
 # IP: 192.168.7.101
 # 端口: 27017
 # 角色: 主节点(可读写)
 # ============================================================
 ​
 # ---------- 系统日志配置 ----------
 systemLog:
   # destination: 日志输出目标,file 表示输出到文件
   destination: file
   # path: 日志文件的完整路径
   path: "/usr/local/mongodb/log/standalone/mongodb.log"
   # logAppend: true 表示每次重启时追加到现有日志文件末尾,而非覆盖
   logAppend: true
 ​
 # ---------- 存储配置 ----------
 storage:
   # dbPath: MongoDB 数据文件存储目录
   dbPath: "/usr/local/mongodb/data/standalone"
 ​
 # ---------- 进程管理配置 ----------
 processManagement:
   # fork: true 表示以后台守护进程方式运行(后台运行)
   fork: true
   # pidFilePath: 保存进程ID(PID)的文件路径,用于管理进程
   pidFilePath: "/usr/local/mongodb/conf/mongod.pid"
 ​
 # ---------- 网络配置 ----------
 net:
   # bindIp: 绑定监听的IP地址
   # 0.0.0.0 表示监听所有网络接口(允许任何IP连接)
   # 生产环境建议改为具体IP,如 192.168.7.101
   bindIp: 0.0.0.0
   # port: MongoDB 服务监听的端口号,默认 27017
   port: 27017
 ​
 # ---------- 副本集配置 ----------
 replication:
   # replSetName: 副本集名称,三台服务器必须保持一致
   # 这里命名为 rs0(replica set 0 的缩写)
   replSetName: rs0

编写从节点的配置文件

 # ============================================================
 # MongoDB 副本集配置文件 - 从节点(SECONDARY)
 # IP: 192.168.7.102
 # 端口: 27017
 # 角色: 从节点(只读,自动同步主节点数据)
 # ============================================================
 ​
 # ---------- 系统日志配置 ----------
 systemLog:
   # destination: 日志输出目标,file 表示输出到文件
   destination: file
   # path: 日志文件的完整路径
   path: "/usr/local/mongodb/log/standalone/mongodb.log"
   # logAppend: true 表示每次重启时追加到现有日志文件末尾,而非覆盖
   logAppend: true
 ​
 # ---------- 存储配置 ----------
 storage:
   # dbPath: MongoDB 数据文件存储目录
   dbPath: "/usr/local/mongodb/data/standalone"
 ​
 # ---------- 进程管理配置 ----------
 processManagement:
   # fork: true 表示以后台守护进程方式运行(后台运行)
   fork: true
   # pidFilePath: 保存进程ID(PID)的文件路径,用于管理进程
   pidFilePath: "/usr/local/mongodb/conf/mongod.pid"
 ​
 # ---------- 网络配置 ----------
 net:
   # bindIp: 绑定监听的IP地址
   # 0.0.0.0 表示监听所有网络接口(允许任何IP连接)
   # 生产环境建议改为具体IP,如 192.168.7.102
   bindIp: 0.0.0.0
   # port: MongoDB 服务监听的端口号,默认 27017
   port: 27017
 ​
 # ---------- 副本集配置 ----------
 replication:
   # replSetName: 副本集名称,三台服务器必须保持一致
   # 这里命名为 rs0(replica set 0 的缩写)
   replSetName: rs0

编写仲裁节点的配置文件

 # ============================================================
 # MongoDB 副本集配置文件 - 仲裁节点(ARBITER)
 # IP: 192.168.7.100
 # 端口: 27017
 # 角色: 仲裁节点(不存储数据,仅参与主节点选举投票)
 # 作用: 当主节点宕机时,协助从节点选举出新的主节点
 # 注意: 仲裁节点不保存任何数据,资源消耗极低
 # ============================================================
 ​
 # ---------- 系统日志配置 ----------
 systemLog:
   # destination: 日志输出目标,file 表示输出到文件
   destination: file
   # path: 日志文件的完整路径
   path: "/usr/local/mongodb/log/standalone/mongodb.log"
   # logAppend: true 表示每次重启时追加到现有日志文件末尾,而非覆盖
   logAppend: true
 ​
 # ---------- 存储配置 ----------
 storage:
   # dbPath: MongoDB 数据文件存储目录
   # 注意: 仲裁节点虽然不存储实际数据,但仍需要此目录存放一些元数据
   dbPath: "/usr/local/mongodb/data/standalone"
 ​
 # ---------- 进程管理配置 ----------
 processManagement:
   # fork: true 表示以后台守护进程方式运行(后台运行)
   fork: true
   # pidFilePath: 保存进程ID(PID)的文件路径,用于管理进程
   pidFilePath: "/usr/local/mongodb/conf/mongod.pid"
 ​
 # ---------- 网络配置 ----------
 net:
   # bindIp: 绑定监听的IP地址
   # 0.0.0.0 表示监听所有网络接口(允许任何IP连接)
   # 生产环境建议改为具体IP,如 192.168.7.100
   bindIp: 0.0.0.0
   # port: MongoDB 服务监听的端口号,默认 27017
   port: 27017
 ​
 # ---------- 副本集配置 ----------
 replication:
   # replSetName: 副本集名称,三台服务器必须保持一致
   # 这里命名为 rs0(replica set 0 的缩写)
   replSetName: rs0

三台机器分别启动 MongoDB

 mongod -f /usr/local/mongodb/conf/standalone/mongodb.conf

仅在主节点(192.168.7.101) 初始化副本集

 # 连接客户端
 mongosh 192.168.7.101:27017
 ​
 # 初始化设置
 rs.initiate({
   _id: "rs0",
   members: [
     { _id: 0, host: "192.168.7.101:27017" },
     { _id: 1, host: "192.168.7.102:27017" },
     { _id: 2, host: "192.168.7.100:27017", arbiterOnly: true }
   ]
 })
 ​
 # 验证集群状态的两个指令
 rs.conf();
 rs.status()
 ​

数据同步测试

 # 连接主节点执行
 mongosh 192.168.7.101:27017
 ​
 # 执行操作
 use testDB
 db.testCollection.insertOne({ name: "测试数据", createTime: new Date() })
 db.testCollection.find()
 ​
 ​
 # 连接从节点执行
 mongosh 192.168.7.102:27017
 ​
 # 开启从节点读权限
 rs.setReadPref("primaryPreferred")
 ​
 # 执行操作
 use testDB
 db.testCollection.find()

再来连接仲裁节点看看情况

 # 连接仲裁节点
 mongosh 192.168.7.100:27017
 ​
 # 测试仲裁节点
 use testDB
 db.testCollection.find()
 MongoServerError: node is not in primary or recovering state
 提示:"当前节点既不是主节点,也不是正在恢复中的从节点,所以无法执行操作。"

外部连接操作

为了外部可以连接,需要开放MongoDB端口、更新防火墙(关闭防火墙也行):

 # 在 public 区域添加规则:永久开放 TCP 端口 27017
 firewall-cmd --zone=public --add-port=27017/tcp --permanent
 ​
 # 重新加载防火墙配置,使新规则立即生效
 firewall-cmd --reload
 ​
 # 列出 public 区域当前所有已开放的端口
 firewall-cmd --zone=public --list-ports

副本集群主从切换

 # 查询mongodb进程
 ps aux | grep mongodb
 ​
 # 在主节点模拟宕机(强杀主节点)
 kill -9 xxxx
 ​
 # 等待几秒钟,去从节点查看
 rs.status();
 ​
 '信息查询解释(主)'
 {
   _id: 0,
   name: '192.168.7.101:27017',
   health: 0,                    // ❌ 不健康
   stateStr: '(not reachable/healthy)',
   lastHeartbeatMessage: 'Error connecting to 192.168.7.101:27017 :: caused by :: Connection refused'
 }
 ​
 '信息查询解释(从)'
 {
   _id: 1,
   name: '192.168.7.102:27017',
   health: 1,                    // ✅ 健康
   stateStr: 'PRIMARY',          // ✅ 已成为新主节点
   self: true                    // 当前连接的节点
 }
 ​
 '信息查询解释(仲裁)'
 {
   _id: 2,
   name: '192.168.7.100:27017',
   health: 1,                    // ✅ 健康
   stateStr: 'ARBITER'           // 仲裁角色不变
 }
 ​
 # 重启主节点
 mongod -f /usr/local/mongodb/conf/standalone/mongodb.conf
 ​
 # 等待几秒钟从节点继续查看状态
 rs.status();
 ​
 '信息查询解释(主)'
 {
   _id: 0,
   name: '192.168.7.101:27017',
   health: 1,                              // ✅ 已恢复健康
   stateStr: 'SECONDARY',                  // 🔄 降级为从节点
   syncSourceHost: '192.168.7.102:27017',  // 📥 从新主节点同步数据
   uptime: 21                              // 刚重启 21 秒
 }
 ​
 '信息查询解释(从)'
 {
   _id: 1,
   name: '192.168.7.102:27017',
   health: 1,
   stateStr: 'PRIMARY',                   // 👑 继续担任主节点
   self: true                             // 当前连接的节点
 }
 ​
 '信息查询解释(仲裁)'
 {
   _id: 2,
   name: '192.168.7.100:27017',
   health: 1,
   stateStr: 'ARBITER'                    // 仲裁角色不变
 }
 ​
 # 将主、从节点都干掉,再在仲裁节点上观察集群的状态
 rs.status();
 ​
 # 当前集群状态
 节点             IP:端口                   角色           状态          健康度
 主节点      192.168.7.102:27017        ~~PRIMARY~~     ❌ 已宕机       health: 0
 从节点      192.168.7.101:27017        ~~SECONDARY~~   ❌ 已宕机       health: 0
 仲裁节点    192.168.7.100:27017          ARBITER        ✅ 正常运行     health: 1


副本集状态诊断

 # 基础状态查看
 rs.status()          // 副本集完整状态(最常用)
 rs.conf()            // 副本集配置信息
 rs.isMaster()        // 当前节点角色信息(快速判断主从)


设置开机自启

 # 编辑文件
 vim /etc/systemd/system/mongod.service
 ​
 # 添加以下内容
 [Unit]
 Description=MongoDB Database Server
 After=network.target
 ​
 [Service]
 Type=forking
 ExecStart=/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/conf/standalone/mongodb.conf
 ExecStop=/usr/local/mongodb/bin/mongod --shutdown --config /usr/local/mongodb/conf/standalone/mongodb.conf
 PIDFile=/usr/local/mongodb/conf/mongod.pid
 Restart=on-failure
 RestartSec=5s
 LimitNOFILE=65536
 ​
 [Install]
 WantedBy=multi-user.target
 ​
 ​
 # 添加后执行
 systemctl daemon-reload
 systemctl enable mongod
 systemctl start mongod