跳到主要内容

认识

2025年02月28日
柏拉文
越努力,越幸运

一、认识


MongoDB 复制(Replication 是通过 副本集(Replica Set 提供数据冗余和高可用性的一种机制。

MongoDB 复制(Replication)优势: 高可用性, 即使主节点故障,副本集仍可自动选举新的主节点; 数据冗余, 多个副本保证数据不会轻易丢失; 读写分离,提升性能, 读请求可以被分发到多个从节点,提高读取吞吐量, 相比传统数据库的主从复制,支持自动选主和更灵活的读写分离。支持故障转移, 发生故障时,副本集能自动选举新的主节点,快速恢复服务,减少运维工作量。

MongoDB 复制(Replication)架构: 副本集通常由 1 个主节点 和 多个从节点 组成。当主节点发生故障, 副本集会自动选举新的主节点,确保 MongoDB 集群的高可用性。副本集 是一组 MongoDB 实例, 包括: 主节点Primary), 负责接收写入请求, 所有写入请求都在此处理,并同步到从节点; 从节点(Secondary, 从主节点复制数据,提供高可用性; 仲裁节点(Arbiter,可选), 不存储数据,仅参与选举,用于维持奇数投票节点,保证选举稳定性, 帮助确定新的主节点。

   [Primary]

┌────┴──────┐
[Secondary] [Secondary]

[Arbiter] (可选)

MongoDB 复制(Replication)工作:

  1. 主节点(Primary)处理写入请求: 所有写入请求都在此处理,并同步到从节点。客户端将数据写入主节点, 主节点将操作日志(oplog)存入 local.oplog.rs 集合。oplog(操作日志) 存储在 local.oplog.rs 集合中,是一个 Capped Collection(固定大小集合),记录所有写操作(insertupdatedelete)。超过 oplog 大小限制的日志 会被自动清理(默认 oplogSize), 如果 Secondary 复制太慢,oplog 超过限制,数据同步会中断!

  2. 从节点(Secondary)异步复制数据: 从节点周期性拉取主节点的 oplog 并按顺序重放主节点的操作, 进行异步同步, 数据最终保持一致。同步成功后, Secondary 提交 ACK 确认, 让 Primary 维护同步进度。但存在一定的 复制延迟, 由于复制是异步的, 从节点数据可能落后于主节点, 导致数据最终一致,导致读写不一致。默认情况下,MongoDB 不等待 Secondary 复制完成, 可以使用 majority(多数派)策略,确保数据写入多个节点, 通过 writeConcern 进行同步复制, 所有写操作都要等待多数副本确认后才返回成功, 提供强一致性,但写入性能较低。

    db.collection.insertOne({ name: "Alice" }, { writeConcern: { w: "majority" } });

    只有大多数节点(>50%)确认写入后,才返回成功。提高数据可靠性,但增加写入延迟。

  3. 故障转移(Failover)机制: 当主节点在超过配置的 electionTimeoutMillis 时间段(默认 10 秒)内未与副本集中的其他节点通信时,一个符合条件的从节点将发起选举,并提名自己成为新的主节点。集群将尝试完成新主节点的选举并恢复其正常运转。选举机制使用 Raft 算法,基于心跳检测和 oplog 追踪。当主节点失效时,MongoDB 自动选举新的主节点:

    1. 节点健康检查(心跳检测): 当主节点在超过配置的 electionTimeoutMillis 时间段(默认 10 秒)内未与副本集中的其他节点通信时,一个符合条件的从节点将发起选举,并提名自己成为新的主节点。

    2. 投票选举(多数派原则,投票数 > 50%: MongoDB 选举基于 Raft 一致性算法, 选举流程: 1. 候选状态(Candidate, 一个 Secondary 发起选举,广播 RequestVote 请求,争取其他 Secondary 支持; 2. 投票阶段, 需要超过 50% 以上节点投票才能当选 Primary; 3. Primary 当选, 获胜节点成为新的 Primary,并接管所有写入请求。补充: 如果副本集成员为偶数时, 仲裁节点(Arbiter)维持奇数投票数,防止投票僵持。

MongoDB 复制(Replication)优化:

  1. 复制延迟优化:

    1. 增加 oplog 大小: oplog 默认大小可能不够,可以增大, db.adminCommand({ replSetResizeOplog: 1, size: 10240 }) // 10GB。超过 oplog 大小限制的日志会被自动清理(默认 oplogSize), 如果 Secondary 复制太慢, 复制速度跟不上, oplog 超过限制,数据同步会中断!

    2. 启用 w: majority 写入策略: 默认情况下,MongoDB 不等待 Secondary 复制完成, 可以使用 majority(多数派)策略,确保数据写入多个节点, 通过 writeConcern 进行同步复制, 所有写操作都要等待多数副本确认后才返回成功, 提供强一致性,但写入性能较低。

      db.collection.insertOne({ name: "Alice" }, { writeConcern: { w: "majority" } });

      只有大多数节点(>50%)确认写入后,才返回成功。提高数据可靠性,但增加写入延迟。

    3. 调整 Secondary 读取优先级: rs.secondaryOk();

    4. 减少 Secondary 复制延迟: 调整 secondaryDelaySecs, 减少 Secondary 同步间隔

    5. 降低 Secondary 复制时的 CPU 限制: mongod --replSet rs0 --oplogSize 20480

  2. 读写分离: 副本集读策略, 在副本集中,默认所有的写请求都在主节点进行,而读请求可以由主节点或从节点处理。 MongoDB 提供不同的读取优先级。默认所有查询都在 Primary 上进行,可能导致主节点压力过大, 优化方案, 将部分查询重定向到 Secondary,提升读性能。可在应用层通过 读偏好(Read Preference 让部分查询走从节点: db.collection.find().readPref("secondaryPreferred");MongoDB 读取策略:

    • primary(默认):只从主节点读取(强一致性)。

    • primaryPreferred:优先从主节点读取,主节点不可用时从从节点读取。

    • secondary:只从从节点读取(读性能高,但可能数据有延迟)。

    • secondaryPreferred:优先从从节点读取,所有从节点不可用时才从主节点读取。

    • nearest:从最接近的节点读取(无论主从)。

  3. 复制速度优化:

    1. 增大从节点的 oplog 读取线程:

      mongod --replSet rs0 --oplogSize 10240
    2. 从节点启用 readPref("nearest"),减少读延迟