Appearance
MongoDB 复制集
复制集(Replica Set)是 MongoDB 实现高可用性的核心机制。它通过多节点数据冗余和自动故障转移,确保在节点故障时服务不中断。复制集是生产环境部署 MongoDB 的最低要求,也是分片集群的基础组件。
1. 复制集架构
1.1 基本架构
一个典型的 MongoDB 复制集由 3 个以上节点组成,包含一个主节点(Primary)和多个从节点(Secondary),可选地包含仲裁节点(Arbiter)。
┌─────────────────────────────────────────────────────────────────┐
│ MongoDB 复制集 │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ │ Primary │──────>│ Secondary │──────>│ Secondary │
│ │ (主节点) │ Oplog │ (从节点1) │ Oplog │ (从节点2) │
│ │ 读写操作 │ │ 只读+复制 │ │ 只读+复制 │
│ └──────────────┘ └──────────────┘ └──────────────┘
│ │
│ │ Heartbeat (心跳,每 2 秒)
│ ▼
│ ┌──────────────┐
│ │ Arbiter │
│ │ (仲裁节点) │
│ │ 仅投票,不存数据
│ └──────────────┘
│ │
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ 客户端驱动程序(自动发现拓扑) ││
│ │ mongodb://host1:27017,host2:27017,host3:27017 ││
│ └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘1.2 节点角色
| 角色 | 说明 | 数量 | 数据存储 |
|---|---|---|---|
| Primary(主节点) | 接收所有写入操作,记录 oplog | 有且仅有一个 | 存储完整数据 |
| Secondary(从节点) | 从 Primary 复制 oplog,提供读服务 | 1 个或多个 | 存储完整数据 |
| Arbiter(仲裁节点) | 参与选举投票,不存储数据 | 0 个或 1 个(可选) | 不存储数据 |
| Hidden(隐藏节点) | 特殊的 Secondary,不提供读服务 | 0 个或多个 | 存储完整数据 |
| Delayed(延迟节点) | 特殊的 Secondary,数据延迟复制 | 0 个或多个 | 存储完整数据 |
隐藏节点(Hidden):
- 优先级为 0,不会成为 Primary
- 不接收客户端读请求(除非直接连接)
- 常用于备份、分析、报表等离线任务
延迟节点(Delayed):
- 故意延迟复制(如延迟 1 小时)
- 可用于防止人为误操作(如误删数据后从延迟节点恢复)
- 也是隐藏节点的一种
1.3 节点数量规则
| 建议 | 说明 |
|---|---|
| 最少 3 个节点 | 实现自动故障转移的最低要求 |
| 奇数个节点 | 避免选举平票(3、5、7...) |
| 最多 50 个节点 | MongoDB 复制集成员上限 |
| 最多 7 个投票节点 | 参与选举的投票节点上限 |
为什么推荐奇数个节点:
| 节点数 | 投票节点 | 多数票 | 容错节点数 |
|---|---|---|---|
| 3 | 3 | 2 | 1 |
| 4 | 4 | 3 | 1 |
| 5 | 5 | 3 | 2 |
4 个节点和 3 个节点容错能力相同(都是 1 个),但 4 个节点多了一个节点成本。因此推荐奇数个节点。
2. Oplog(操作日志)
2.1 Oplog 概述
Oplog(Operations Log)是复制集的核心组件,记录 Primary 上所有数据变更操作。Secondary 节点通过读取和重放 Primary 的 oplog 来同步数据。
Oplog 特性:
| 特性 | 说明 |
|---|---|
| 存储位置 | local 数据库的 oplog.rs 集合 |
| 集合类型 | 上限集合(Capped Collection) |
| 内容格式 | 幂等操作(如 $set、$unset 而非直接赋值) |
| 记录范围 | 仅记录数据变更,不记录查询 |
| 按时间排序 | 操作按时间戳自然排序存放 |
Oplog 文档示例:
javascript
{
"ts": Timestamp(1670000000, 1), // 操作时间戳
"t": NumberLong(1), // term(选举任期)
"h": NumberLong("1234567890"), // 操作哈希值
"v": 2, // oplog 版本
"op": "i", // 操作类型:i=insert, u=update, d=delete, c=command, n=noop
"ns": "test.orders", // 命名空间(数据库.集合)
"ui": UUID("..."), // 集合 UUID
"wall": ISODate("2026-01-15T..."), // 墙上时钟时间
"o": { ... }, // 操作内容
"o2": { ... } // 更新操作的查询条件
}操作类型(op 字段):
| op 值 | 含义 | 说明 |
|---|---|---|
| "i" | insert | 插入操作 |
| "u" | update | 更新操作 |
| "d" | delete | 删除操作 |
| "c" | command | 数据库命令(如 createIndex、dropDatabase) |
| "n" | noop | 空操作(用于心跳、新节点选举通知) |
2.2 Oplog 大小配置
javascript
// 查看 oplog 信息
rs.printReplicationInfo();
// 输出示例
// configured oplog size: 2048 MB
// log length start to end: 3600 secs (1.00 hrs)
// oplog first event time: Mon Jan 15 2026 08:00:00 GMT+0800
// oplog last event time: Mon Jan 15 2026 09:00:00 GMT+0800
// now: Mon Jan 15 2026 09:05:00 GMT+0800Oplog 大小建议:
| 场景 | 推荐大小 | 说明 |
|---|---|---|
| 开发环境 | 1-2 GB | 小规模数据 |
| 一般生产 | 5-10 GB | 可覆盖数小时的操作 |
| 大写入量 | 20-50 GB | 高写入吞吐量场景 |
| 极大规模 | 50+ GB | 超大集群,频繁维护 |
Oplog 大小的意义:
- Oplog 窗口(Oplog Window)= Oplog 大小 / 写入速率
- 如果 Secondary 的复制延迟超过 Oplog 窗口,Secondary 将无法通过增量同步追上,需要全量同步(Initial Sync)
- 典型 Oplog 窗口建议为 24 小时以上
2.3 Oplog 监控命令
javascript
// 查看 oplog 状态(主节点)
rs.printReplicationInfo();
// 查看从节点复制状态
rs.printSecondaryReplicationInfo();
// 直接查询 oplog
use local;
db.oplog.rs.find().sort({ $natural: -1 }).limit(5);
// 查询特定时间范围的 oplog
db.oplog.rs.find({
ts: {
$gte: Timestamp(1670000000, 0),
$lte: Timestamp(1670086400, 0)
}
});
// 查看 oplog 当前大小
db.oplog.rs.stats().maxSize;3. 数据同步
3.1 初始同步(Initial Sync)
当一个新的 Secondary 节点加入复制集时,需要进行初始同步以获取完整数据集。
初始同步过程:
1. 克隆数据库
├── 选择一个同步源(通常是 Primary 或较新的 Secondary)
├── 遍历源节点的所有数据库和集合
└── 复制所有文档到本地
2. 应用 oplog
├── 记录克隆开始时的 oplog 时间戳
├── 克隆完成后,应用从该时间戳到当前的所有 oplog
└── 确保数据一致性
3. 构建索引
├── 为每个集合创建索引
└── 索引构建期间的写入操作会排队
4. 切换到 Secondary 模式
├── 开始实时复制 oplog
└── 节点状态变为 SECONDARY初始同步耗时因素:
| 因素 | 影响 |
|---|---|
| 数据量大小 | 数据越多,克隆时间越长 |
| 网络带宽 | 带宽不足会显著延长同步时间 |
| 磁盘 I/O | 源节点读和目标节点写都会影响速度 |
| 索引数量 | 索引越多,构建时间越长 |
| oplog 窗口 | 如果克隆期间 oplog 被覆盖,需要重新开始 |
初始同步优化:
- 使用文件系统快照(如 LVM snapshot)替代常规初始同步
- 从一个空闲的 Secondary 进行同步,而非 Primary
- 确保网络带宽充足
3.2 增量同步(Incremental Sync)
初始同步完成后,Secondary 节点通过持续读取并重放 Primary 的 oplog 来保持数据同步。
增量同步过程:
Primary 写入数据
└── 写入 oplog
└── Secondary 持续读取 oplog
├── 批量获取 oplog 条目
├── 多线程应用(默认 16 个线程)
└── 更新本地 oplog 时间戳复制延迟监控:
javascript
// 查看复制延迟
rs.printSecondaryReplicationInfo();
// 通过 rs.status() 查看
rs.status().members.forEach(m => {
print(`Node: ${m.name}, Lag: ${m.optimeDate - m.lastHeartbeat}`);
});复制延迟原因:
| 原因 | 说明 | 解决方案 |
|---|---|---|
| 网络延迟 | 跨地域复制 | 就近部署,使用网络优化 |
| 写入量过大 | Secondary 追赶不上 | 增加 oplog 大小,优化写入 |
| 磁盘 I/O 慢 | Secondary 磁盘性能差 | 升级磁盘(SSD),独立存储 |
| 索引构建 | 构建大索引阻塞复制 | 滚动构建索引 |
| 计算资源不足 | CPU/内存不够 | 扩容或优化资源分配 |
4. 选举机制
4.1 Raft 协议
MongoDB 的选举机制基于 Raft 共识算法,确保在 Primary 故障时能快速选出新的 Primary。
选举触发条件:
| 触发场景 | 说明 |
|---|---|
| Primary 宕机 | 心跳超时,Secondary 发起选举 |
| Primary 网络隔离 | 网络分区导致 Primary 无法与多数节点通信 |
| 手动降级 | 执行 rs.stepDown() 命令 |
| 新节点加入 | 新节点加入触发选举测试 |
| 配置变更 | 修改复制集配置后 |
4.2 心跳(Heartbeat)
复制集节点之间每 2 秒发送一次心跳(Heartbeat),用于检测节点存活状态。
心跳参数:
| 参数 | 默认值 | 说明 |
|---|---|---|
| heartbeatIntervalMillis | 2000 | 心跳间隔(毫秒) |
| electionTimeoutMillis | 10000 | 选举超时(毫秒) |
心跳超时判断:
Secondary 连续 10 秒未收到 Primary 心跳
├── 认为自己与 Primary 失去连接
├── 检查自己是否有资格成为 Primary(优先级 > 0、数据足够新)
└── 发起选举4.3 优先级(Priority)
每个节点都有一个优先级(Priority),影响选举结果。优先级越高,越容易成为 Primary。
javascript
// 设置节点优先级
cfg = rs.conf();
cfg.members[0].priority = 2; // 主节点优先级更高
cfg.members[1].priority = 1; // 次要节点
cfg.members[2].priority = 0; // 永远不会成为 Primary
rs.reconfig(cfg);优先级规则:
| priority 值 | 含义 | 使用场景 |
|---|---|---|
| 0 | 永远不会成为 Primary | 隐藏节点、延迟节点、备份节点 |
| 0.5 | 低优先级 | 备用 Primary(性能较差的节点) |
| 1 | 默认优先级 | 普通节点 |
| > 1 | 高优先级 | 期望成为 Primary 的节点(如硬件更好) |
| 最大值 | 1000 | 配置上限 |
4.4 Term(任期)
Term 是 Raft 协议中的概念,每次选举会增加 Term 值。Term 用于防止脑裂和确保数据一致性。
Term 的作用:
- 每次成功的选举,Term 加 1
- 所有写入操作都携带当前 Term
- 具有更高 Term 的节点不会被低 Term 节点覆盖
- 写入冲突时,高 Term 的写入优先
查看 Term:
javascript
// 查看当前 Term
rs.status().members.forEach(m => {
print(`Node: ${m.name}, Term: ${m.optime && m.optime.t}`);
});4.5 选举过程
1. 心跳超时(10 秒未收到 Primary 心跳)
└── 检查是否有资格成为 Primary
├── priority > 0
├── 数据足够新(oplog 时间戳不能落后太多)
└── 能与多数节点通信
2. 发起选举(Request Vote)
├── 向所有有投票权的节点发送投票请求
└── 等待投票结果
3. 投票
├── 每个节点最多投一票
├── 检查候选节点的 oplog 是否比自己新
├── 检查当前 Term 是否匹配
└── 投票给符合条件的候选节点
4. 选举结果
├── 获得多数票 → 成为 Primary
├── 未获得多数票 → 等待下一轮选举
└── 平票 → 重新选举(随机延迟后)选举时间估算:
| 阶段 | 时间 | 说明 |
|---|---|---|
| 心跳超时 | ~10 秒 | 检测到 Primary 失效 |
| 选举过程 | ~1-5 秒 | 投票和协商 |
| 总计 | ~12-15 秒 | 从故障到新 Primary 就绪 |
5. 写关注(Write Concern)
5.1 写关注级别
写关注定义了写入操作需要多少个节点确认才算成功。
javascript
{ w: <value>, j: <boolean>, wtimeout: <number> }| w 值 | 含义 | 容错 | 延迟 |
|---|---|---|---|
| 0 | 不等待确认 | 无 | 最低 |
| 1 | Primary 确认 | 故障时可能丢失 | 低 |
| 2 | 2 个节点确认 | 1 个节点故障 | 中 |
| "majority" | 大多数节点确认 | 大多数-1 个节点故障 | 中 |
| <tag> | 指定标签的节点确认 | 取决于标签 | - |
写关注与复制集大小:
| 复制集节点数 | "majority" 含义 | 所需节点数 |
|---|---|---|
| 3 | 3/2 + 1 = 2 | 2 个节点 |
| 5 | 5/2 + 1 = 3 | 3 个节点 |
| 7 | 7/2 + 1 = 4 | 4 个节点 |
5.2 Journal(j: true)
javascript
// 写入操作需要写入 journal 日志后才确认
db.orders.insertOne(
{ orderNo: "ORD001" },
{ writeConcern: { w: "majority", j: true } }
);Journal 的作用:
- Journal 是 WiredTiger 的预写日志(WAL),每 50ms 刷盘一次
- 开启
j: true后,写入确认会等待 journal 刷盘 - 即使发生断电,写入的数据也不会丢失
- 但会增加写入延迟(约 50ms)
5.3 自定义写关注(Write Concern Tags)
javascript
// 配置节点标签
cfg = rs.conf();
cfg.members[0].tags = { dc: "sz", rack: "rack1" };
cfg.members[1].tags = { dc: "sz", rack: "rack2" };
cfg.members[2].tags = { dc: "gz", rack: "rack1" };
rs.reconfig(cfg);
// 定义自定义写关注
cfg.settings = {
getLastErrorModes: {
"twoDC": { dc: 2 }, // 至少两个不同数据中心确认
"twoRack": { rack: 2 } // 至少两个不同机架确认
}
};
rs.reconfig(cfg);
// 使用自定义写关注
db.orders.insertOne(
{ orderNo: "ORD001" },
{ writeConcern: { w: "twoDC", j: true, wtimeout: 5000 } }
);6. 读偏好(Read Preference)
6.1 读偏好模式
| 模式 | 说明 | 使用场景 |
|---|---|---|
| primary | 只从 Primary 读取 | 需要强一致性的读取 |
| primaryPreferred | 优先 Primary,不可用时读 Secondary | 大多数读取场景 |
| secondary | 只从 Secondary 读取 | 报表、分析、备份 |
| secondaryPreferred | 优先 Secondary,不可用时读 Primary | 降低 Primary 压力 |
| nearest | 读取网络延迟最低的节点 | 地理分布式部署 |
6.2 读偏好使用
javascript
// 连接字符串中设置
// mongodb://host1:27017,host2:27017,host3:27017/?readPreference=secondaryPreferred
// 单个查询设置
db.orders.find({ status: "pending" }).readPref("secondary");
// 指定标签
db.orders.find({ status: "pending" }).readPref(
"secondary",
[{ dc: "sz" }] // 只从深圳数据中心的 Secondary 读取
);6.3 读偏好与一致性
| 读偏好 | 读关注 | 一致性 |
|---|---|---|
| primary | "local" | 强一致性 |
| primary | "majority" | 强一致性 |
| secondary | "local" | 可能读到旧数据 |
| secondary | "majority" | 多数节点已确认的数据 |
| secondary | "available" | 任意可用数据 |
7. 读关注(Read Concern)
7.1 读关注级别
| 级别 | 含义 | 适用场景 |
|---|---|---|
| "local" | 返回节点本地最新数据,不保证已复制 | 默认级别,低延迟 |
| "available" | 返回节点可用数据,可能不一致 | 分片集群低延迟 |
| "majority" | 返回已复制到大多数节点的数据 | 需要读一致性的场景 |
| "linearizable" | 线性一致读,保证读取最新数据 | 金融、余额等强一致性场景 |
| "snapshot" | 快照隔离,事务内使用 | 多文档事务 |
7.2 读关注使用示例
javascript
// 多数读关注
db.orders.find({ status: "pending" }).readConcern("majority");
// 线性一致读(需要 w: "majority" 的写入配合)
db.accounts.findOne({ _id: "ACC001" }).readConcern("linearizable");
// 快照读(事务内)
const session = client.startSession();
session.startTransaction({
readConcern: { level: "snapshot" },
writeConcern: { w: "majority" }
});7.3 读关注与写关注的组合
| 写入(w) | 读取(readConcern) | 保证 |
|---|---|---|
| 1 | "local" | 可能读到未提交的数据 |
| "majority" | "local" | 可能读到稍旧的数据 |
| "majority" | "majority" | 读到的数据不会回滚 |
| "majority" | "linearizable" | 读到的数据一定是最新的 |
8. 自动故障转移
8.1 故障转移过程
1. Primary 宕机
└── Secondary 心跳超时(10 秒)
└── 检测到 Primary 不可用
2. 选举新 Primary
├── 有资格的 Secondary 发起选举
├── 获得多数票的节点成为新 Primary
└── 新 Primary 通知所有节点
3. 客户端重连
├── 驱动程序检测到连接断开
├── 自动发现新的 Primary
└── 重新发送未完成的写入操作(如果使用可重试写入)
4. 旧 Primary 恢复
├── 重新加入复制集
├── 作为 Secondary 追赶 oplog
└── 复制落后时回滚冲突操作8.2 回滚(Rollback)
当旧 Primary 恢复后,如果它有一些操作未被复制到大多数节点,这些操作会被回滚。
回滚发生条件:
- Primary 接收了写入操作
- 写入操作未复制到大多数节点(w: 1 或 w: 2 但不足 majority)
- Primary 宕机,新 Primary 选举
- 旧 Primary 恢复,发现自己的 oplog 与新 Primary 的 oplog 有分歧
回滚的文件:
bash
# 回滚的数据保存在 rollback 目录
ls /data/db/rollback/
# rollback-<timestamp>-<uuid>.bson回滚数据恢复:
bash
# 使用 mongorestore 恢复回滚数据
mongorestore --db test --collection orders rollback/rollback-xxx.bson避免回滚:
- 使用
w: "majority"写关注:写入操作必须被大多数节点确认,不会回滚 - 使用
{ j: true }写关注:即使 Primary 宕机,journal 中的数据不会丢失
8.3 可重试写入(Retryable Writes,3.6+)
javascript
// 连接字符串中启用可重试写入
// mongodb://host:27017/?retryWrites=true
// 驱动程序自动重试
// 故障转移期间,驱动程序会自动重试写入操作
// 确保写入操作不会因为临时故障而丢失可重试写入的限制:
- 仅支持单文档写入操作(insertOne、updateOne、deleteOne、findOneAndXxx)
- 不支持 bulkWrite 和 insertMany
- 需要 session 支持
- 重试有超时限制
9. 复制集部署
9.1 部署配置
yaml
# mongod.conf(复制集配置)
replication:
replSetName: "rs0" # 复制集名称
oplogSizeMB: 5120 # oplog 大小(MB)
net:
port: 27017
bindIp: 0.0.0.0
storage:
dbPath: /data/db
journal:
enabled: true
wiredTiger:
engineConfig:
cacheSizeGB: 89.2 初始化复制集
javascript
// 连接到第一个节点
// mongo --host host1:27017
// 初始化复制集
rs.initiate({
_id: "rs0",
members: [
{ _id: 0, host: "host1:27017", priority: 2 },
{ _id: 1, host: "host2:27017", priority: 1 },
{ _id: 2, host: "host3:27017", priority: 1 }
]
});
// 如果是已有的单节点,需要先初始化
rs.initiate();9.3 添加和移除节点
javascript
// 添加新节点
rs.add("host4:27017");
// 添加仲裁节点
rs.addArb("host5:27017");
// 移除节点
rs.remove("host4:27017");
// 重新配置
cfg = rs.conf();
cfg.members[3].priority = 0; // 修改现有节点配置
rs.reconfig(cfg);9.4 生产环境部署建议
| 建议 | 说明 |
|---|---|
| 至少 3 个数据节点 | 实现高可用最低要求 |
| 奇数个节点 | 避免选举平票 |
| 节点分布在不同的物理机 | 避免单点故障 |
| 不同机架/可用区 | 提高容灾能力 |
| 使用专用网络 | 减少网络延迟和丢包 |
| 配置监控和告警 | 及时发现节点异常 |
| 定期备份 | 即使有复制集也需要备份 |
| 配置 oplog 足够大 | 避免 Secondary 需要全量同步 |
| 使用 DNS 或主机名 | 而非 IP 地址,方便迁移 |
10. 复制集监控
10.1 rs.status()
javascript
rs.status();
// 关键字段解读
{
set: "rs0",
members: [
{
_id: 0,
name: "host1:27017",
health: 1, // 0=宕机, 1=健康
state: 1, // 1=PRIMARY, 2=SECONDARY, 7=ARBITER
stateStr: "PRIMARY",
uptime: 86400,
optime: { ts: Timestamp(...), t: NumberLong(1) },
optimeDate: ISODate("..."),
syncSourceHost: "", // 同步源(Primary 为空)
syncSourceId: -1,
infoMessage: "",
configVersion: 1,
self: true // 当前连接的节点
},
{
_id: 1,
name: "host2:27017",
health: 1,
state: 2,
stateStr: "SECONDARY",
uptime: 86400,
optime: { ts: Timestamp(...), t: NumberLong(1) },
optimeDate: ISODate("..."),
lastHeartbeat: ISODate("..."), // 上次心跳时间
lastHeartbeatRecv: ISODate("..."), // 上次收到心跳时间
pingMs: NumberLong(0), // 网络延迟(毫秒)
syncSourceHost: "host1:27017", // 同步源
syncSourceId: 0,
infoMessage: "",
configVersion: 1
}
]
}节点状态(state 字段):
| state | stateStr | 说明 |
|---|---|---|
| 0 | STARTUP | 启动中 |
| 1 | PRIMARY | 主节点 |
| 2 | SECONDARY | 从节点 |
| 3 | RECOVERING | 恢复中 |
| 5 | STARTUP2 | 初始同步完成,加载索引 |
| 6 | UNKNOWN | 未知状态 |
| 7 | ARBITER | 仲裁节点 |
| 8 | DOWN | 不可达 |
| 9 | ROLLBACK | 回滚中 |
| 10 | REMOVED | 已移除 |
10.2 rs.printReplicationInfo()
javascript
rs.printReplicationInfo();
// 输出示例
// configured oplog size: 5120 MB
// log length start to end: 86400 secs (24.00 hrs)
// oplog first event time: Mon Jan 14 2026 10:00:00 GMT+0800
// oplog last event time: Mon Jan 15 2026 10:00:00 GMT+0800
// now: Mon Jan 15 2026 10:05:00 GMT+080010.3 rs.printSecondaryReplicationInfo()
javascript
rs.printSecondaryReplicationInfo();
// 输出示例
// source: host2:27017
// syncedTo: Mon Jan 15 2026 10:05:00 GMT+0800
// 0 secs (0 hrs) behind the primary10.4 关键监控指标
| 指标 | 获取方式 | 告警阈值 |
|---|---|---|
| 复制延迟 | rs.printSecondaryReplicationInfo() | > 10 秒 |
| Oplog 窗口 | rs.printReplicationInfo() | < 1 小时 |
| 节点健康状态 | rs.status().members[].health | health = 0 |
| 节点状态 | rs.status().members[].state | state != 1/2/7 |
| 网络延迟 | rs.status().members[].pingMs | > 10ms(同机房) |
| 复制集写关注 | 监控写入确认时间 | 超时 |
11. 常见问题与解决方案
11.1 脑裂(Split Brain)
问题:网络分区导致两个节点都认为自己是 Primary。
解决方案:
- MongoDB 使用 Raft 协议,只有获得多数票的节点才能成为 Primary
- 网络分区后,被隔离的少数节点不会成为 Primary(因为无法获得多数票)
- 确保节点数为奇数,避免平票
11.2 复制延迟过大
问题:Secondary 延迟严重,数据不一致。
解决方案:
- 检查网络延迟和带宽
- 增加 oplog 大小
- 优化 Secondary 的磁盘 I/O(使用 SSD)
- 减少 Secondary 的读负载
- 调整 Secondary 复制线程数
11.3 Oplog 被覆盖
问题:Secondary 离线时间过长,oplog 已被覆盖。
解决方案:
- 执行全量初始同步(Initial Sync)
- 或使用文件系统快照恢复
- 预防:设置足够大的 oplog
12. 总结
复制集是 MongoDB 生产部署的基石,提供数据冗余、高可用和读扩展能力。
关键要点回顾:
- 复制集架构:1 Primary + N Secondary + 可选 Arbiter,最小 3 节点
- Oplog:上限集合,记录所有数据变更,Secondary 通过重放 oplog 同步数据
- 选举:基于 Raft,心跳超时 10 秒,获得多数票成为 Primary
- 写关注:w: "majority" 保证数据不丢失,j: true 保证断电不丢数据
- 读偏好:按需选择 Primary 或 Secondary 读取,平衡一致性和性能
- 读关注:majority 保证读取的数据不会回滚,linearizable 保证最新
- 故障转移:自动检测、自动选举、自动恢复,约 12-15 秒完成
- 监控:使用 rs.status()、rs.printReplicationInfo() 等命令监控复制集状态
