MongoDB 复制(副本集)

MongoDB 复制(Replica Set)全面指南

MongoDB 的 副本集(Replica Set) 是实现 高可用(HA)数据冗余读写分离 的核心机制。一个副本集由多个节点组成,相互复制数据,其中 一个主节点(Primary) 接受写操作,其余 从节点(Secondary) 实时同步数据。


一、核心概念

术语说明
Primary(主节点)唯一接受写操作的节点,选举产生
Secondary(从节点)从 Primary 同步数据,可提供读操作
Arbiter(仲裁节点)只参与选举,不存数据,仅用于避免脑裂
Oplog(Operation Log)主节点记录所有写操作的日志,从节点通过 oplog 拉取变更
Replication Lag从节点落后主节点的延迟时间
Election(选举)当 Primary 宕机时,自动选举新的 Primary

二、副本集架构示例

[Primary] ←── oplog ──→ [Secondary 1]
   ↑                           ↓
   └── oplog ──→ [Secondary 2]   (可选)
   └── vote ──→ [Arbiter]        (仅参与选举)

三、搭建副本集(3 节点示例)

1. 配置文件(mongod.conf

# node1.conf (端口 27017)
net:
  port: 27017
replication:
  replSetName: rs0
storage:
  dbPath: /data/rs0-1

# node2.conf (端口 27018)
net:
  port: 27018
replication:
  replSetName: rs0
storage:
  dbPath: /data/rs0-2

# node3.conf (端口 27019)
net:
  port: 27019
replication:
  replSetName: rs0
storage:
  dbPath: /data/rs0-3

2. 启动节点

mongod --config node1.conf
mongod --config node2.conf
mongod --config node3.conf

3. 初始化副本集(在任意节点执行)

// 连接到 node1
mongosh --port 27017

// 初始化
rs.initiate({
  _id: "rs0",
  members: [
    { _id: 0, host: "localhost:27017" },
    { _id: 1, host: "localhost:27018" },
    { _id: 2, host: "localhost:27019" }
  ]
})

4. 验证状态

rs.status()        // 查看整体状态
rs.isMaster()      // 当前节点角色
rs.conf()          // 配置信息

四、节点状态一览

状态说明
PRIMARY可读写
SECONDARY可读,同步中
STARTUP初始同步
STARTUP2正在应用 oplog
RECOVERING恢复中(不可读)
ARBITER仲裁节点
DOWN / UNKNOWN失联
rs.status().members.forEach(m => print(`${m.name}: ${m.stateStr}`))

五、读写操作与读偏好(Read Preference)

读偏好说明适用场景
primary默认,只读主节点强一致性
primaryPreferred优先主,失败则读从高可用读
secondary只读从节点减轻主节点压力
secondaryPreferred优先从,主不可用时读主推荐用于查询
nearest读延迟最低的节点跨地域部署

连接字符串示例

// 读从节点(推荐用于报表)
mongodb://host1:27017,host2:27018,host3:27019/mydb?replicaSet=rs0&readPreference=secondaryPreferred

代码中使用

// Node.js (mongodb driver)
const client = new MongoClient(uri, {
  readPreference: ReadPreference.SECONDARY_PREFERRED
})

六、写关注(Write Concern)

控制写操作确认的副本数量。

选项说明
{ w: 1 }默认,只确认主节点
{ w: 2 }主 + 1 个从节点确认
{ w: "majority" }大多数节点确认
{ wtimeout: 5000 }超时时间(ms)
db.collection.insertOne(
  { item: "box" },
  { writeConcern: { w: "majority", wtimeout: 5000 } }
)

七、Oplog 详解

  • 存储在 local 数据库的 capped collection: oplog.rs
  • 每个写操作记录为一条文档
  • 从节点通过 tailable cursor 拉取 oplog
// 查看 oplog 大小
db.getSiblingDB("local").oplog.rs.stats()

// 查看最新操作
db.getSiblingDB("local").oplog.rs.find().sort({ $natural: -1 }).limit(5)

注意:oplog 太小会导致从节点无法追上主节点 → 需重新全量同步!


八、常见运维操作

1. 添加节点

rs.add("newhost:27017")

2. 删除节点

rs.remove("oldhost:27018")

3. 重新配置(调整优先级、投票)

cfg = rs.conf()
cfg.members[0].priority = 2   // 提升为首选主节点
cfg.members[1].votes = 0      // 取消投票权(转为纯从)
rs.reconfig(cfg)

4. 强制重新选举(stepDown)

rs.stepDown(60)  // 主节点退位 60 秒

5. 冻结节点(暂停选举)

rs.freeze(300)  // 300 秒内不参与选举

九、故障演练与恢复

场景操作预期
主节点宕机关闭 Primary自动选举新主
从节点延迟暂停同步rs.printSecondaryReplicationInfo() 显示 lag
网络分区断开网络可能触发选举或降级
// 查看同步延迟
rs.printSecondaryReplicationInfo()

十、高级配置建议

1. 优先级(Priority):控制谁更容易当选主节点

{ _id: 0, host: "host1:27017", priority: 2 }  // 高优先级
{ _id: 1, host: "host2:27018", priority: 1 }
{ _id: 2, host: "host3:27019", priority: 0.5 }

2. 隐藏节点(Hidden):用于备份、分析

{ 
  _id: 3, 
  host: "backup:27020", 
  priority: 0, 
  hidden: true, 
  votes: 0 
}

客户端需显式设置 readPreference 才能访问。

3. 延迟节点(Delayed):灾备用

{ 
  _id: 4, 
  host: "dr:27021", 
  priority: 0, 
  slaveDelay: 3600,  // 延迟 1 小时
  hidden: true 
}

十一、监控关键指标

指标说明工具
repl lag同步延迟rs.status()
oplog windowoplog 可支持的追赶时间rs.printReplicationInfo()
election time选举耗时日志
connections连接数db.serverStatus().connections
asserts错误计数db.serverStatus().asserts
// 一键查看 oplog 窗口
rs.printReplicationInfo()

十二、与分片(Sharding)关系

  • 副本集是分片的基础
  • 每个分片(shard)是一个副本集
  • 配置服务器(config server)也是一个副本集
  • 路由进程(mongos)不存储数据
mongos > shard1 (replset) > shard2 (replset)

十三、常见问题排查

问题检查点
从节点 RECOVERINGoplog 太小 / 网络中断 / 磁盘满
无法选举多数节点不可达 / 票数不足
写操作慢w: majority + 高延迟
数据不一致检查 readConcern / 回滚

十四、实战脚本:一键部署 3 节点副本集(Docker)

# docker-compose.yml
version: '3.8'
services:
  mongo1:
    image: mongo:7
    command: --replSet rs0 --bind_ip_all
    ports: [27017:27017]
    volumes: [./data1:/data/db]
  mongo2:
    image: mongo:7
    command: --replSet rs0 --bind_ip_all
    ports: [27018:27017]
    volumes: [./data2:/data/db]
  mongo3:
    image: mongo:7
    command: --replSet rs0 --bind_ip_all
    ports: [27019:27017]
    volumes: [./data3:/data/db]
docker-compose up -d
# 初始化
mongosh --port 27017 --eval 'rs.initiate({_id:"rs0", members:[{ _id:0, host:"host.docker.internal:27017"}, { _id:1, host:"host.docker.internal:27018"}, { _id:2, host:"host.docker.internal:27019"}]})'

十五、学习资源


你想实现什么?

  • 搭建测试环境?
  • 配置读写分离?
  • 灾备延迟节点?
  • 跨机房副本集?

欢迎贴出你的 架构图 / 业务需求,我可以给出 完整配置 + 自动化脚本

文章已创建 2371

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部