3. 副本集架构与容灾基础
MongoDB 的高可用能力来自副本集(Replica Set)。副本集不是简单的“主从复制”,而是一组共同维护同一份数据、通过心跳与选举决定谁可写的 mongod 进程集合。理解 primary、secondary、arbiter 三种角色的职责边界,以及选举、写关注(writeConcern)、读关注(readConcern)如何共同决定数据安全,是后续备份恢复与容灾设计的地基。
三种角色:谁存数据、谁投票、谁可写
副本集默认由至少三个成员组成,典型结构是“一主两从”。Primary 是当前唯一接受写操作的节点,它把客户端写入记录到自己的 oplog(操作日志),secondary 通过持续拉取 oplog 并重放来保持数据一致。Secondary 默认只读(需设置 readPreference 才可读),它既是数据副本,也是选举中的投票者。Arbiter 不保存数据、不参与复制,只参与投票,用于以较低成本凑够奇数票数,但它无法在 primary 故障时接管成为 primary。
这里有一个常被忽视的容灾含义:如果三成员是“一主一从一仲裁”,那么当 primary 宕机,唯一剩下的数据节点 secondary 可以被选举为 primary,但此时整个副本集只剩一份数据,没有任何冗余。因此仲裁者适合“预算有限、能接受短暂单副本风险”的场景,而不适合对数据安全要求高的核心库。生产环境更推荐三数据节点(PSS)或五数据节点结构。
选举机制:多数派是硬约束
副本集成员之间每 2 秒发送一次心跳。当 secondary 在 electionTimeoutMillis(默认 10 秒)内没有收到 primary 心跳,就会认为 primary 不可用,发起选举。选举采用多数派原则:候选节点必须获得超过总投票成员半数的票数才能成为 primary。三成员副本集需要 2 票,五成员需要 3 票。
这个“多数派”规则直接决定了容灾能力。三成员副本集最多允许 1 个投票成员故障;如果同时宕机 2 个,剩余 1 个节点无法凑够 2 票,副本集会进入只读状态,无法选出新 primary。因此,节点数量与故障容忍度的关系是:容忍故障数 = floor((N-1)/2)。三成员容忍 1 个,五成员容忍 2 个。这也是为什么生产环境常采用五成员或“三数据节点 + 跨机房分布”的原因。
选举还受 priority 影响。priority 高的节点在条件相同时优先当选,可用于把 primary 固定在资源更好的机房。但要注意:priority 只影响“谁更可能当选”,不能突破多数派约束。此外,如果节点数据落后太多(oplog 差距过大),它可能无法被选为 primary,因为其他成员会拒绝为其投票,避免数据回滚风险。
写关注:决定“写成功”的含义
写关注(writeConcern)回答的是:一次写入在什么条件下才算成功返回给客户端。常用取值如下:
w:1:只要 primary 写入内存即返回。速度最快,但 primary 宕机且数据未复制时可能丢失。w:"majority":写入被多数投票成员确认后才返回。三成员需 2 个确认,五成员需 3 个确认。这是生产环境推荐值。w:0:不等待任何确认,仅发出即返回,可靠性最低。j:true:要求写入落到 journal 日志后才确认,防止断电丢数据。
写关注与容灾的关系可以用一个判断来概括:w:"majority" 保证“已确认的写入”在多数派中至少存在一份。当 primary 故障、新 primary 从多数派中选出时,已确认的数据不会丢失。而 w:1 只保证 primary 自己收到,一旦 primary 在复制完成前宕机,这部分数据就可能随回滚消失。
读关注:决定“读到什么”
读关注(readConcern)回答的是:读取时能看到哪个阶段的数据。常见级别包括:
local:默认值,读取节点当前本地数据,可能读到尚未被多数派确认、未来可能回滚的数据。majority:只读取已被多数派确认的数据,保证读到的数据不会回滚。linearizable:最强一致性,保证读到最新已确认写入,但延迟高、仅适用于单文档读。snapshot:用于多文档事务,读取某个一致快照。
读关注必须与读偏好(readPreference)配合理解。如果使用 readPreference: secondary 从从节点读,同时 readConcern 为 local,就可能读到落后于 primary 的数据,甚至读到之后会被回滚的数据。对账务、库存等场景,应使用 readConcern: "majority" 配合 primary 读,或至少确保读路径不会读到未确认数据。
组合判断:数据安全等级速查
| 写关注 | 读关注 | 典型风险 | 适用场景 |
|---|---|---|---|
| w:1 | local | primary 宕机可能丢已确认写;可能读到回滚数据 | 日志、缓存、可容忍丢失的数据 |
| w:"majority" | local | 写入安全,但读可能读到未确认数据 | 写多读少、读一致性要求不高的场景 |
| w:"majority" + j:true | majority | 延迟较高,但已确认数据不丢、不回滚 | 订单、支付、库存等核心业务 |
| w:"majority" | linearizable | 延迟最高,仅单文档读 | 需要强一致读的关键判断 |
w:"majority" 与 readConcern:"majority";副本集至少三个数据节点,避免“一主一从一仲裁”承载核心数据;跨机房部署时,把多数派放在主机房,同时评估网络分区下的可用性。