这是《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()
关注:
- oplog 窗口;
- 写入速率;
- Secondary 落后时间;
- 大事务对 oplog 的影响;
- 全量同步窗口。
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()
常见原因:
- Secondary 磁盘慢;
- 网络带宽不足;
- Secondary 承担重查询;
- 大量写入;
- 大事务;
- 索引构建;
- 资源抢占;
- 初始同步。
治理:
- 监控复制延迟;
- 控制 Secondary 负载;
- 延迟敏感读不走 Secondary;
- 避免大事务;
- 提升硬件和网络。
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 生产清单
- 至少三个数据节点;
- 跨机架、可用区或机房部署;
- 奇数投票成员;
- 监控复制延迟和选举;
- 合理配置 oplog;
- 关键写使用 majority;
- Secondary 读有延迟预算;
- 备份节点不承担重负载;
- 变更前确认多数健康;
- 定期演练主节点故障。
本章小结
副本集通过 oplog 复制和多数派选举提供高可用。生产上必须关注投票拓扑、oplog 窗口、复制延迟、读写关注和故障域分布。Secondary 能扩展读能力,但一致性由读偏好和读关注共同决定。
思考题
- 为什么三数据节点比两数据节点加 Arbiter 更稳?
- Oplog 太小会带来什么问题?
- majority 写关注是否表示所有节点都持久化?
- 什么业务适合 Secondary 读?
- 失去多数派后为什么不能继续写入?