MongoDBNotes

第 14 章:副本集

zjc 于 2026-01-14 发布

这是《MongoDB 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 副本集是 MongoDB 高可用的基础形态,由一个 Primary 和多个 Secondary 组成。Primary 接收写入,Secondary 同步 oplog,Primary 故障时投票节点选举新 Primary。

14.1 架构

Client
  -> Primary
       | oplog
       +--> Secondary 1
       +--> Secondary 2

成员类型:

成员 说明
Primary 接收写操作
Secondary 同步数据,可提供读
Priority 0 永不成为 Primary
Hidden 对应用不可见,可做报表或备份
Delayed 延迟同步,用于误操作恢复
Arbiter 只投票不存数据

生产常用三数据节点副本集,不建议长期依赖 Arbiter 提供多数派。

14.2 Oplog

Oplog 是固定大小集合,记录可幂等重放的变更:

use local
db.oplog.rs.find().sort({ $natural: -1 }).limit(3)

查看大小:

db.printReplicationInfo()

关注:

  1. oplog 窗口;
  2. 写入速率;
  3. Secondary 落后时间;
  4. 大事务对 oplog 的影响;
  5. 全量同步窗口。

oplog 太小可能导致 Secondary 掉队后无法增量同步。

14.3 部署副本集

三个节点配置:

replication:
  replSetName: rs0

net:
  bindIp: 0.0.0.0
  port: 27017

security:
  keyFile: /etc/mongo-keyfile
  authorization: enabled

初始化:

rs.initiate({
  _id: "rs0",
  members: [
    { _id: 0, host: "mongo1:27017", priority: 2 },
    { _id: 1, host: "mongo2:27017", priority: 1 },
    { _id: 2, host: "mongo3:27017", priority: 1 }
  ]
})

状态:

rs.status()
rs.conf()
db.hello()

14.4 复制流程

client write
  -> primary apply
  -> write local oplog
  -> replicate to secondary
  -> secondary apply oplog
  -> ack according to write concern
  -> primary return success

写关注:

db.orders.insertOne(
  { _id: "o_1", status: "CREATED" },
  { writeConcern: { w: "majority", wtimeout: 3000 } }
)

majority 确认多数节点收到写入,但应用层仍需处理超时后的状态确认。

14.5 复制延迟

查看:

rs.printSecondaryReplicationInfo()

常见原因:

  1. Secondary 磁盘慢;
  2. 网络带宽不足;
  3. Secondary 承担重查询;
  4. 大量写入;
  5. 大事务;
  6. 索引构建;
  7. 资源抢占;
  8. 初始同步。

治理:

  1. 监控复制延迟;
  2. 控制 Secondary 负载;
  3. 延迟敏感读不走 Secondary;
  4. 避免大事务;
  5. 提升硬件和网络。

14.6 Secondary 读取

连接字符串:

mongodb://user:pass@mongo1,mongo2,mongo3/shop?replicaSet=rs0&readPreference=secondaryPreferred

示例:

场景 策略
订单写后立即读 primary
用户画像分析 secondaryPreferred
报表 hidden secondary
就近读 nearest
强一致读 primary 或 linearizable

Secondary 读带来扩展读能力,但应用必须接受复制延迟。

14.7 成员维护

调整优先级:

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

添加节点:

rs.add("mongo4:27017")

移除节点:

rs.remove("mongo4:27017")

维护节点时应逐步操作,确认复制状态和选举多数,避免同时下线过多投票节点。

14.8 读关注

常见 Read Concern:

级别 说明
local 本节点已应用的数据
majority 多数节点已提交的数据
linearizable 强一致读,条件更多
available 分片路由场景的可用性取向

示例:

db.orders.find(
  { _id: "o_1" }
).readConcern("majority")

读关注、写关注和读偏好组合决定一致性语义。

14.9 故障场景

故障 影响
Primary 宕机 触发选举,短暂不可写
Secondary 宕机 读容量下降
两个数据节点宕机 三节点副本集失去多数
网络分区 多数侧可服务
Oplog 窗口不足 Secondary 需要全量同步
复制延迟高 Secondary 读过期

多数节点不可用时,副本集变为只读或不可服务,这是避免脑裂的代价。

14.10 生产清单

  1. 至少三个数据节点;
  2. 跨机架、可用区或机房部署;
  3. 奇数投票成员;
  4. 监控复制延迟和选举;
  5. 合理配置 oplog;
  6. 关键写使用 majority;
  7. Secondary 读有延迟预算;
  8. 备份节点不承担重负载;
  9. 变更前确认多数健康;
  10. 定期演练主节点故障。

本章小结

副本集通过 oplog 复制和多数派选举提供高可用。生产上必须关注投票拓扑、oplog 窗口、复制延迟、读写关注和故障域分布。Secondary 能扩展读能力,但一致性由读偏好和读关注共同决定。

思考题

  1. 为什么三数据节点比两数据节点加 Arbiter 更稳?
  2. Oplog 太小会带来什么问题?
  3. majority 写关注是否表示所有节点都持久化?
  4. 什么业务适合 Secondary 读?
  5. 失去多数派后为什么不能继续写入?