01. 副本集是什么
副本集(Replica Set)是 MongoDB 实现高可用的核心机制——多个 mongod 进程组成一个集群,一个主节点处理所有写入,多个从节点实时同步数据。
主节点挂了怎么办?——副本集自动选举产生新的主节点,整个过程中应用可能短暂不可用(几秒到十几秒),但数据不丢、服务自动恢复。这就是高可用的含义:单点故障不导致服务中断。
副本集最少需要 3 个节点(1 主 2 从)或 2 个节点加 1 个仲裁者(只投票不存数据)。为什么是奇数?因为选举需要多数派(超过半数)——偶数节点可能分裂成平票两个阵营谁也选不出来。
应用端连副本集:连接字符串里写所有节点地址,驱动自动发现主节点。主节点变了驱动自动切换连接。
bash
# 启动副本集(每个节点都要指定相同的 replSet)
mongod --replSet myReplSet --port 27017 --dbpath /data/rs1
mongod --replSet myReplSet --port 27018 --dbpath /data/rs2
mongod --replSet myReplSet --port 27019 --dbpath /data/rs3
# 在任一节点上初始化副本集
mongosh --port 27017
rs.initiate({
_id: "myReplSet",
members: [
{ _id: 0, host: "localhost:27017" },
{ _id: 1, host: "localhost:27018" },
{ _id: 2, host: "localhost:27019" }
]
});副本集成员数最好是奇数。如果只有 2 个数据节点,加一个仲裁者(arbiter)——它不存数据只投票,资源消耗极小。
02. 复制流程——Oplog 机制
MongoDB 的复制基于 Oplog(操作日志)。主节点把所有的写操作(增删改)记录到 oplog 里,从节点持续拉取 oplog 并在本地重放。
Oplog 是一个固定大小的集合(capped collection),存在 local 数据库的 oplog.rs 里。满了就覆盖最老的记录。如果从节点落后太多,oplog 已经滚过了,从节点就追不上需要全量同步。
Oplog 大小默认是空闲磁盘的 5%(最小 990MB,最大 50GB)。高写入场景要调大 oplog,避免从节点追不上。
从节点拉取 oplog 是异步的,所以主从之间会有延迟(Replication Lag)。延迟大小取决于写入量、网络速度、从节点性能。
javascript
// 查看 oplog 信息
use local;
db.oplog.rs.stats();
// 查看 oplog 最新一条
db.oplog.rs.find().sort({ $natural: -1 }).limit(1);
// 查看复制状态
rs.printReplicationInfo(); // 主节点:oplog 大小和时间
rs.printSecondaryReplicationInfo(); // 各从节点的复制延迟rs.printReplicationInfo() 能看到 oplog 能保存多长时间的操作记录。如果时间太短,从节点容易追不上。
03. 读写分离与 Read Preference
默认情况下从节点不处理读请求——所有读写都走主节点。但可以配置 Read Preference 让读请求分散到从节点,减轻主节点压力。
Read Preference 模式:
primary(默认)——所有读走主节点
primaryPreferred——优先读主,主挂了读从
secondary——只读从节点
secondaryPreferred——优先读从,从都挂了读主
nearest——读网络延迟最低的节点
读写分离的代价:可能读到旧数据。因为从节点异步同步,你读从节点时可能数据还没同步过来。对实时性要求高的场景(如余额查询)不适合读从节点。
javascript
// 应用端设置 Read Preference
// Node.js 驱动示例
const client = new MongoClient(uri, {
readPreference: "secondaryPreferred"
});
// mongosh 单次查询设置
// 注意:以下为概念示意
db.orders.find().readPref("secondary");读从节点可能拿到旧数据。如果你的业务逻辑是写后立即读(比如下单后立即查订单),务必读主节点。
04. 自动故障转移与选举
副本集能在主节点挂掉后自动选出新主,这个过程叫故障转移。选主流程基于 Raft 共识算法:
1. 从节点发现连不上主节点(心跳超时,默认 10 秒)
2. 从节点发起选举,向其他节点拉票
3. 拿到大于半数票的从节点成为新主
4. 其他节点自动从新主同步
选举优先级可以通过 priority 参数调整:priority 高的节点更容易当选主。priority 设为 0 的节点永远不会当选主(适合放在性能差的机器上做纯从库)。
votes 参数控制节点是否有投票权。hidden 参数可以把节点隐藏(客户端读不到),适合做专用的备份或分析节点。
javascript
// 查看副本集状态
rs.status();
// 查看当前配置
rs.conf();
// 调整成员优先级
const cfg = rs.conf();
cfg.members[1].priority = 2; // 提高被选为主的概率
cfg.members[2].priority = 0; // 永远不会当主
rs.reconfig(cfg);05. 副本集运维要点
副本集日常运维需要注意:
1. 监控复制延迟——用 rs.printSecondaryReplicationInfo() 或 Prometheus 监控。延迟高说明从库追不上,可能影响读写分离或故障转移。
2. 定期检查 Oplog 窗口——确保 oplog 足够大,从节点即使短暂断网也能追回来。高写入场景 oplog 至少能存 24 小时的记录。
3. 备份策略——通常从从节点做备份,不影响主节点性能。但备份时要记录 oplog 位置,方便做时间点恢复。
4. 滚动升级——升级 MongoDB 版本时,先升级从节点,再切主然后升级原主。保证服务不中断。
5. 扩容——添加新节点用 rs.add(),新节点会自动初始同步(全量拷贝加增量 oplog)。初始同步期间新节点不可用。
javascript
// 添加新成员
rs.add("localhost:27020");
// 移除成员
rs.remove("localhost:27020");
// 添加仲裁者
rs.addArb("localhost:27021");
// 手动降主(维护前把主切走)
rs.stepDown();rs.stepDown() 让当前主节点主动退位,触发选举。做维护操作前的标准流程——先降主再操作。
知识测验
第 1/5 题正确 0
副本集最少需要几个节点?
下一节
下一节 分片集群