MongoDB 副本集(Replica Set)搭建与运维完整指南

MongoDB 副本集(Replica Set)搭建与运维完整指南

一、副本集核心概念

1.1 什么是副本集

副本集是 MongoDB 官方的高可用集群方案,由多台 MongoDB 实例组成,数据全量同步,具备自动故障转移、读写分离能力。

  • 对应 MySQL 的「主从集群」,但自带自动选举、故障自愈,无需额外中间件。

  • 所有节点数据完全一致,不是分片拆分数据(分片是另一种集群)。

    1.2 核心角色

    | 角色 | 说明 |

    | ------------------ | --------------------------------------- |

    | Primary(主节点) | 唯一接收写入操作的节点,所有增删改都必须走主节点;同时也可提供读服务 |

    | Secondary(从节点) | 实时同步主节点数据,分担读压力;主节点宕机后可参与选举成为新主 |

    | Arbiter(仲裁节点) | 不存数据,只参与投票选举,用于凑齐奇数节点,节省服务器资源(不推荐核心业务用) |

    1.3 核心机制:oplog 操作日志

  • 全称 operations log,是一个固定大小的环形集合,记录所有数据写入操作(增、删、改)。

  • 每个节点本地都保存一份 oplog,不是只有主节点才有。

  • 从节点持续拉取主节点的 oplog,在本地回放执行,实现数据同步。

  • 选举新主时,以「谁的 oplog 最新」为核心依据,保证新主数据最完整。

    1.4 为什么必须是奇数个节点

    副本集选举需要「多数派(过半节点同意)」才能选出新主:

  • 2 节点:挂 1 台,剩余 1 台不足半数,无法选举,集群彻底不可写。

  • 3 节点:挂 1 台,剩余 2 台满足多数派,可正常选举和写入。

  • 生产环境最低标准:3 节点副本集


二、前置准备与环境规划

2.1 环境要求

  • MongoDB 版本:推荐 5.0 / 6.0 LTS 稳定版

  • 操作系统:Linux(CentOS 7+/Ubuntu 20.04+)为主,Windows 仅适合本地测试

  • 磁盘:数据盘建议 SSD,延迟越低同步性能越好

  • 内存:建议 8G 以上,MongoDB 依赖内存缓存提升性能

    2.2 服务器规划(3 节点标准方案)

    以商城生产环境为例:

    | 节点角色 | 内网 IP | 配置建议 | 选举优先级 |

    | ------- | ------------ | --------- | ------------ |

    | 主节点(高配) | 192.168.1.10 | 8C16G 高性能 | priority: 10 |

    | 从节点 1 | 192.168.1.11 | 4C8G | priority: 1 |

    | 从节点 2 | 192.168.1.12 | 4C8G | priority: 1 |

    优先级作用:高配节点宕机恢复后,数据同步完成会自动抢回主节点身份。

    2.3 网络与端口要求

  1. 默认端口:27017,所有节点之间内网互通。

  2. 防火墙放行:三台机器互相开放 27017 端口(仅内网,禁止公网直连)。

  3. 禁止使用 127.0.0.1 绑定地址,否则跨机器无法通信。

  4. 生产环境必须开启身份认证 + 副本集密钥文件,防止非法节点加入。


三、MongoDB 安装与基础配置

3.1 安装 MongoDB(以 Linux 为例)

  1. 配置官方 yum/apt 源,安装稳定版:

    
    # CentOS 示例
    
    cat > /etc/yum.repos.d/mongodb-org-6.0.repo << EOF
    
    [mongodb-org-6.0]
    
    name=MongoDB Repository
    
    baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/6.0/x86_64/
    
    gpgcheck=1
    
    enabled=1
    
    gpgkey=https://www.mongodb.org/static/pgp/server-6.0.asc
    
    EOF
    
    yum install -y mongodb-org
    
    
  2. 默认文件路径:

  • 配置文件:/etc/mongod.conf

  • 数据目录:/var/lib/mongo

  • 日志目录:/var/log/mongodb

    3.2 核心配置文件详解

    /etc/mongod.conf 是 MongoDB 唯一核心配置文件,以下是生产级标准配置,逐行解释:

    
    # 网络配置
    
    net:
    
    port: 27017
    
    bindIp: 0.0.0.0 # 允许所有内网IP访问,生产建议指定具体内网IP段
    
    maxIncomingConnections: 2000 # 最大连接数
    
    # 存储配置
    
    storage:
    
    dbPath: /var/lib/mongo # 数据文件存放路径
    
    journal:
    
    enabled: true # 开启日志,断电不丢数据
    
    wiredTiger:
    
    engineConfig:
    
    cacheSizeGB: 8 # 内存缓存大小,建议设为物理内存的一半
    
    # 日志配置
    
    systemLog:
    
    destination: file
    
    logAppend: true
    
    path: /var/log/mongodb/mongod.log # 日志文件路径
    
    # ====== 开启副本集的关键配置 ======
    
    replication:
    
    replSetName: "mall_rs" # 副本集名称,所有节点必须完全一致
    
    oplogSizeMB: 10240 # oplog 大小,单位MB,建议设为磁盘的5%~10%
    
    

    关键说明:

    • 不写 replication.replSetName = 单机模式,没有副本集能力,也不会生成 oplog。
    • oplogSizeMB 太小会导致宕机恢复时日志被覆盖,无法增量同步,只能全量重传。

    3.3 启动与停止命令

    
    # 启动服务
    
    systemctl start mongod
    
    # 设置开机自启
    
    systemctl enable mongod
    
    # 查看状态
    
    systemctl status mongod
    
    # 重启服务
    
    systemctl restart mongod
    
    

四、场景一:本地测试环境搭建(单机器多端口模拟)

适合本地开发调试,一台机器启动 3 个 MongoDB 实例,模拟 3 节点副本集。

4.1 创建数据与日志目录


mkdir -p /data/mongo_rs/{n1,n2,n3}

mkdir -p /data/mongo_rs/log

4.2 编写 3 份配置文件

分别创建 mongod_n1.confmongod_n2.confmongod_n3.conf,仅端口和数据目录不同,副本集名一致。

示例 mongod_n1.conf


net:

 port: 27017

 bindIp: 127.0.0.1

storage:

 dbPath: /data/mongo_rs/n1

 journal:

 enabled: true

systemLog:

 destination: file

 logAppend: true

 path: /data/mongo_rs/log/n1.log

replication:

 replSetName: "mall_rs"

 oplogSizeMB: 1024

n2 端口改 27018,路径改 n2;n3 端口改 27019,路径改 n3。

4.3 分别启动 3 个实例


mongod -f /data/mongo_rs/mongod_n1.conf

mongod -f /data/mongo_rs/mongod_n2.conf

mongod -f /data/mongo_rs/mongod_n3.conf

4.4 初始化副本集

连接其中一个节点(比如 27017):


mongosh --port 27017

执行初始化命令:


rs.initiate({

 _id: "mall_rs", // 必须和配置文件的 replSetName 完全一致

 members: [

 { _id: 0, host: "127.0.0.1:27017", priority: 10 },

 { _id: 1, host: "127.0.0.1:27018", priority: 1 },

 { _id: 2, host: "127.0.0.1:27019", priority: 1 }

 ]

})

返回 { ok: 1 } 表示初始化成功。

4.5 验证集群状态


// 查看集群状态,确认谁是 PRIMARY

rs.status()

// 查看完整配置

rs.conf()

// 查看 oplog 信息

rs.printReplicationInfo()

  • 状态字段 stateStrPRIMARY 表示主节点,SECONDARY 表示从节点。

  • 初始化完成后,命令行前缀会自动变成 mall_rs [primary]>mall_rs [secondary]>


五、场景二:生产环境多机部署

5.1 每台机器修改配置文件

三台机器分别修改 /etc/mongod.conf,保证:

  1. replSetName: "mall_rs" 完全相同;

  2. bindIp 允许内网访问;

  3. oplogSizeMB 设置合理(建议 10G 以上)。

    修改完成后,三台机器分别启动 MongoDB:

    
    systemctl start mongod
    
    systemctl enable mongod
    
    

    5.2 初始化副本集(在任意一台执行即可)

    登录 192.168.1.10 的 MongoDB:

    
    mongosh --host 192.168.1.10 --port 27017
    
    

    执行初始化:

    
    rs.initiate({
    
    _id: "mall_rs",
    
    members: [
    
    { _id: 0, host: "192.168.1.10:27017", priority: 10 },
    
    { _id: 1, host: "192.168.1.11:27017", priority: 1 },
    
    { _id: 2, host: "192.168.1.12:27017", priority: 1 }
    
    ]
    
    })
    
    

    初始化成功后,配置会自动同步到另外两台节点,无需重复操作。

    5.3 生产安全加固(必做)

    步骤1:创建管理员用户

    在主节点执行:

    
    use admin
    
    db.createUser({
    
    user: "admin",
    
    pwd: "你的强密码",
    
    roles: [ { role: "root", db: "admin" } ]
    
    })
    
    

    步骤2:生成副本集密钥文件

    密钥用于节点之间内部认证,防止非法节点混入集群。

    
    # 生成密钥文件
    
    openssl rand -base64 756 > /data/mongo_keyfile
    
    chmod 400 /data/mongo_keyfile
    
    chown mongod:mongod /data/mongo_keyfile
    
    

    将该文件完全相同地复制到三台机器的相同路径

    步骤3:配置文件开启认证

    三台机器的 mongod.conf 追加:

    
    security:
    
    authorization: enabled
    
    keyFile: /data/mongo_keyfile
    
    

    重启三台 MongoDB 服务生效。


六、副本集核心配置与管理

6.1 调整选举优先级

让高配机器宕机恢复后自动变回主节点。


// 1. 获取当前配置

cfg = rs.conf()

// 2. 修改第0个节点(192.168.1.10)的优先级

cfg.members[0].priority = 10

// 3. 应用配置

rs.reconfig(cfg)

注意:

  • priority 取值 0~1000,数值越高越容易当选主节点。
  • priority = 0 的节点永远不会成为主节点,适合纯备份、报表节点。
  • 旧主恢复后,必须先追平 oplog 数据,才会触发重新选举。

6.2 手动切换主节点

维护主节点时,手动让当前主节点退位:


// 让当前主节点退位 300 秒,期间不会重新参选

rs.stepDown(300)

执行后集群会自动选出新主,高优先级节点会优先当选。

6.3 新增 / 移除节点


// 新增从节点

rs.add("192.168.1.13:27017")

// 新增仲裁节点

rs.addArb("192.168.1.14:27017")

// 移除节点

rs.remove("192.168.1.13:27017")

6.4 调整 oplog 大小

运行中也可在线调整,无需重启:


use local

db.adminCommand({ replSetResizeOplog: 1, size: 20480 }) // 单位MB,设为20G


七、Node.js + Mongoose 连接副本集

7.1 完整连接代码


const mongoose = require('mongoose');

// 副本集连接地址:所有节点IP都写上,指定 replicaSet 名称

const uri = "mongodb://admin:密码@192.168.1.10:27017,192.168.1.11:27017,192.168.1.12:27017/mall?replicaSet=mall_rs&authSource=admin";

mongoose.connect(uri, {

 maxPoolSize: 100, // 连接池大小

 readPreference: "secondaryPreferred", // 默认读偏好:优先从从节点读

 writeConcern: { w: "majority" } // 写入安全:多数节点确认才返回成功

});

const db = mongoose.connection;

db.on('error', console.error.bind(console, '连接错误:'));

db.once('open', () => {

 console.log('MongoDB 副本集连接成功');

});

7.2 读写偏好(readPreference)详解

| 模式 | 说明 | 适用场景 |

| -------------------- | ----------- | ------------- |

| primary | 只从主节点读 | 强一致要求、写后立刻查 |

| primaryPreferred | 优先主节点,主挂了读从 | 要求一致性但兼顾可用性 |

| secondary | 只从从节点读 | 非实时统计、报表、历史数据 |

| secondaryPreferred | 优先从节点,从挂了读主 | 默认推荐,兼顾性能与可用性 |

7.3 写后立刻查:强制读主库最佳实践

这是解决主从延迟、查不到刚插入数据的标准方案。


const Order = mongoose.model('Order', orderSchema);

// 1. 写入订单(自动走主节点)

const newOrder = await Order.create({

 userId: 1001,

 amount: 99.9,

 status: 'pending'

});

// 2. 强制读主节点,保证一定能查到刚写入的数据

const orderDetail = await Order.findById(newOrder._id).read('primary');

// 3. 普通历史列表查询,自动走从节点(全局默认 secondaryPreferred)

const orderList = await Order.find({ userId: 1001 }).sort({ createTime: -1 });

7.4 写入安全级别 writeConcern

| 级别 | 说明 | 适用场景 |

| --------------- | -------------- | --------------- |

| w: 1 | 主节点写入成功就返回(默认) | 性能优先,可接受极小概率丢数据 |

| w: "majority" | 多数节点写入成功才返回 | 订单、支付等核心数据,宕机不丢 |

| w: 0 | 不等待确认,发出去就完事 | 日志、埋点等可丢失数据 |

商城订单、支付、用户余额建议统一使用 w: "majority"


八、读写分离业务规范(直接落地)

8.1 必须强制读主(.read('primary'))的场景

  1. 新增数据后立即回显详情(下单成功页、创建后详情)

  2. 更新数据后立即校验状态(支付回调、退款后刷新、取消订单)

  3. 事务内的所有查询

  4. 库存、余额、金额等强一致性数据查询

  5. 后台管理系统刚提交修改后的详情查询

    8.2 推荐读从库的场景

  6. 用户历史订单列表、分页查询

  7. 商品列表、详情页(非实时库存)

  8. 数据统计、报表导出

  9. 日志、埋点、行为记录查询

  10. 大数据分析、离线计算


九、故障模拟与恢复流程

9.1 从节点宕机与恢复

现象:主节点正常,业务写入不受影响;读请求自动避开故障节点。

恢复流程

  1. 修复故障机器,启动 MongoDB 服务;

  2. 节点自动连接集群,识别当前主节点;

  3. 对比本地 oplog 位点,拉取宕机期间缺失的日志,增量回放;

  4. 数据追平后自动恢复为 SECONDARY,重新承接读请求。

    注意:如果宕机太久,oplog 已被覆盖,节点会自动触发全量重同步。

    9.2 主节点宕机与自动选举

    现象

  5. 剩余从节点通过心跳检测到主节点失联(默认 10 秒超时);

  6. 存活节点发起投票,选出 oplog 最新、优先级最高的节点成为新主;

  7. Mongoose 驱动自动感知新主,写入请求无缝切换。

    业务影响:选举期间(几秒内)不可写入,选举完成后自动恢复。

    9.3 旧主节点恢复后的自动切回

  8. 旧主修复启动,发现集群已有新主,自动降级为 SECONDARY;

  9. 拉取新主的 oplog,追平所有宕机期间的数据;

  10. 因为自身 priority 更高,数据同步完成后自动触发重新选举;

  11. 重新成为 PRIMARY,业务写入自动切回高配机器。

    9.4 极端场景:oplog 覆盖后的全量重同步

    如果从节点宕机时间超过 oplog 保留时长,无法增量同步,执行手动重同步:

    
    # 1. 停止故障节点 MongoDB
    
    # 2. 清空数据目录
    
    rm -rf /var/lib/mongo/*
    
    # 3. 启动 MongoDB,节点会自动从主节点全量复制数据
    
    systemctl start mongod
    
    

十、运维注意事项与最佳实践

10.1 数据一致性保障

  • 核心业务写入开启 w: "majority",杜绝宕机丢数据;

  • 写后实时查询强制读主,避免延迟导致业务 bug;

  • 禁止直接向从节点写入数据(MongoDB 默认拒绝,但要防止权限误配)。

    10.2 核心监控指标

  1. 副本集状态:节点数量、主节点是否存在、节点是否健康

  2. 复制延迟:主从 oplog 时间差,正常应在 1 秒内

  3. oplog 窗口:oplog 可保留的时长,建议至少 24 小时

  4. 连接数、内存使用率、磁盘使用率

    10.3 备份策略

  • 每日全量备份 + 实时 oplog 备份,支持任意时间点恢复

  • 备份从从节点执行,不影响主库性能

  • 定期演练备份恢复流程

    10.4 扩容原则

  • 读压力大:增加从节点数量

  • 写压力/数据量过大:升级为分片集群(Sharded Cluster)

  • 节点数量保持奇数,避免脑裂


十一、常见问题排查

11.1 节点无法加入集群

  • 检查 replSetName 是否完全一致(大小写敏感)

  • 检查网络互通、端口是否放行

  • 检查密钥文件权限是否为 400、内容是否完全一致

  • 检查 MongoDB 版本是否一致

    11.2 从节点无法读取数据

  • MongoDB 从节点默认拒绝读请求,需通过驱动设置 readPreference

  • Shell 中测试需执行 rs.slaveOk()db.getMongo().setReadPref('secondary')

    11.3 同步延迟过高

  • 从节点硬件配置过低,CPU/磁盘 IO 跟不上

  • 主节点大批量写入、大事务操作

  • 网络带宽不足、延迟高

  • oplog 太小,频繁循环覆盖

    11.4 选举失败

  • 存活节点不足半数

  • 所有节点时间不同步(建议配置 NTP 时间同步)

  • 节点之间网络分区,无法互相通信


十二、关键避坑总结

  1. 默认启动是单机:必须配置 replSetName 才是副本集,才有 oplog 和自动选举。

  2. 节点数量必须奇数:2 台机器无法容错,最低标准 3 节点。

  3. 延迟必然存在:任何主从架构都有延迟,靠强制读主解决写后查问题,不是靠框架自动处理。

  4. 高配机器设高 priority:宕机恢复后自动切回主节点,不用手动干预。

  5. 生产必须开认证:禁止裸奔部署,密钥文件 + 用户认证双保险。


本文由萧兮的博客原创发布,欢迎转载,转载务必保留原文链接。

萧兮的博客https://www.20010515.xyz · 原文:https://www.20010515.xyz/posts/019ef296-2194-7401-9dce-fb96d6554067