MongoDB副本集

副本集(Replica Set) 是MongoDB中用于提高数据可用性和容错能力的一种机制

副本集是一个包含多个MongoDB实例的集群,有一个主节点,和一个或多个从节点,主节点负责处理所有写入操作,从节点定期复制主节点数据保持数据一致性

副本集类型和角色

两种类型

主节点(Primary)类型:数据操作的主要连接点,可读写。

从节点(Secondary)类型:数据冗余备份节点,可以读或选举。
三种角色

主要成员(Primary):接收所有写操作,就是主节点。

副本成员(Replicate):从主节点通过复制操作以维护相同的数据集,即备份数据,不可写操作,可以读操作

仲裁者(Arbiter):不保留任何数据的副本,只具有投票选举作用

副本集和传统主从集群对比

特性 副本集 (Replica Set) 主从复制 (Master-Slave)
架构本质 自动化高可用集群 手动配置的数据复制
故障转移 自动选举:主节点故障时,从节点自动投票选举新主节点 手动切换:需要管理员干预将从节点提升为主节点
节点管理 动态角色:所有节点对等,角色由系统自动分配 静态配置:主从角色在启动时固定
数据一致性 强一致性保障:支持写关注,防止数据回滚 弱一致性:无内置机制确保写操作安全
客户端连接 智能路由:客户端连接副本集名称,驱动自动发现主节点 硬编码:应用需要直接指定主节点地址
MongoDB官方状态 推荐标准(当前版本唯一支持的高可用方案) 已废弃(不再维护)

副本集本质上是主从复制的自动化升级版本。它保留了主从的数据复制机制,但增加了选举、心跳检测、自动故障恢复等分布式系统功能。

对于现代应用需求,副本集在可用性、可靠性和运维效率上全面优于传统主从复制,因此 MongoDB 已用副本集完全取代主从复制模式。

副本集创建

1. Docker Compose一键启动

使用 Docker Compose 一键启动一个包含3个节点的副本集,并进行初始化。

yaml 复制代码
version: '3.8'

services:
  mongo1:
    image: mongo:latest
    container_name: mongo1
    restart: always
    ports:
      - "27017:27017" # 将主节点映射到本地端口,方便连接
    command: mongod --replSet myReplicaSet --bind_ip_all
    networks:
      - mongo-network

  mongo2:
    image: mongo:latest
    container_name: mongo2
    restart: always
    ports:
      - "27018:27017" # 第二个节点映射到不同端口
    command: mongod --replSet myReplicaSet --bind_ip_all
    networks:
      - mongo-network

  mongo3:
    image: mongo:latest
    container_name: mongo3
    restart: always
    ports:
      - "27019:27017" # 第三个节点映射到不同端口
    command: mongod --replSet myReplicaSet --bind_ip_all
    networks:
      - mongo-network

networks:
  mongo-network:
    driver: bridge

2. 启动副本集容器

bash 复制代码
docker-compose up -d


3. 初始化副本集

连接到任一容器实例

bash 复制代码
docker exec -it mongo1 mongosh

执行初始化命令

bash 复制代码
rs.initiate(
  {
    _id: "myReplicaSet",
    members: [
      { _id: 0, host: "mongo1:27017" },
      { _id: 1, host: "mongo2:27017" },
      { _id: 2, host: "mongo3:27017" }
    ]
  }
)

这里用的 host 是 容器名:端口,因为它们在 Docker 自定义网络内可以通过容器名互相发现。

查看副本集状态

bash 复制代码
rs.status()

members 数组下的每个成员的 stateStr 字段,包含一个 "PRIMARY",两个 "SECONDARY"。

bash 复制代码
members: [
    {
      _id: 0,
      name: 'mongo1:27017',
      health: 1,
      state: 1,
      stateStr: 'PRIMARY',
      uptime: 135,
      optime: { ts: Timestamp({ t: 1758793236, i: 1 }), t: Long('1') },
      optimeDate: ISODate('2025-09-25T09:40:36.000Z'),
      optimeWritten: { ts: Timestamp({ t: 1758793236, i: 1 }), t: Long('1') },
      optimeWrittenDate: ISODate('2025-09-25T09:40:36.000Z'),
      lastAppliedWallTime: ISODate('2025-09-25T09:40:36.349Z'),
      lastDurableWallTime: ISODate('2025-09-25T09:40:36.349Z'),
      lastWrittenWallTime: ISODate('2025-09-25T09:40:36.349Z'),
      syncSourceHost: '',
      syncSourceId: -1,
      infoMessage: 'Could not find member to sync from',
      electionTime: Timestamp({ t: 1758793206, i: 1 }),
      electionDate: ISODate('2025-09-25T09:40:06.000Z'),
      configVersion: 1,
      configTerm: 1,
      self: true,
      lastHeartbeatMessage: ''
    },
    {
      _id: 1,
      name: 'mongo2:27017',
      health: 1,
      state: 2,
      stateStr: 'SECONDARY',
      uptime: 44,
      optime: { ts: Timestamp({ t: 1758793236, i: 1 }), t: Long('1') },
      optimeDurable: { ts: Timestamp({ t: 1758793236, i: 1 }), t: Long('1') },
      optimeWritten: { ts: Timestamp({ t: 1758793236, i: 1 }), t: Long('1') },
      optimeDate: ISODate('2025-09-25T09:40:36.000Z'),
      optimeDurableDate: ISODate('2025-09-25T09:40:36.000Z'),
      optimeWrittenDate: ISODate('2025-09-25T09:40:36.000Z'),
      lastAppliedWallTime: ISODate('2025-09-25T09:40:36.349Z'),
      lastDurableWallTime: ISODate('2025-09-25T09:40:36.349Z'),
      lastWrittenWallTime: ISODate('2025-09-25T09:40:36.349Z'),
      lastHeartbeat: ISODate('2025-09-25T09:40:38.279Z'),
      lastHeartbeatRecv: ISODate('2025-09-25T09:40:39.283Z'),
      pingMs: Long('0'),
      lastHeartbeatMessage: '',
      syncSourceHost: 'mongo1:27017',
      syncSourceId: 0,
      infoMessage: '',
      configVersion: 1,
      configTerm: 1
    },
    {
      _id: 2,
      name: 'mongo3:27017',
      health: 1,
      state: 2,
      stateStr: 'SECONDARY',
      uptime: 44,
      optime: { ts: Timestamp({ t: 1758793236, i: 1 }), t: Long('1') },
      optimeDurable: { ts: Timestamp({ t: 1758793236, i: 1 }), t: Long('1') },
      optimeWritten: { ts: Timestamp({ t: 1758793236, i: 1 }), t: Long('1') },
      optimeDate: ISODate('2025-09-25T09:40:36.000Z'),
      optimeDurableDate: ISODate('2025-09-25T09:40:36.000Z'),
      optimeWrittenDate: ISODate('2025-09-25T09:40:36.000Z'),
      lastAppliedWallTime: ISODate('2025-09-25T09:40:36.349Z'),
      lastDurableWallTime: ISODate('2025-09-25T09:40:36.349Z'),
      lastWrittenWallTime: ISODate('2025-09-25T09:40:36.349Z'),
      lastHeartbeat: ISODate('2025-09-25T09:40:38.277Z'),
      lastHeartbeatRecv: ISODate('2025-09-25T09:40:39.281Z'),
      pingMs: Long('0'),
      lastHeartbeatMessage: '',
      syncSourceHost: 'mongo1:27017',
      syncSourceId: 0,
      infoMessage: '',
      configVersion: 1,
      configTerm: 1
    }
  ],

4.主从复制验证

在主节点上插入数据

bash 复制代码
use testdb
db.testcoll.insertOne({ name: "Hello Replica Set!", value: 1 })

在从节点上读取数据,连接从节点,设置允许从从节点读后查询数据

bash 复制代码
docker exec -it mongo2 mongosh
db.getMongo().setReadPref('secondaryPreferred')
use testdb
db.testcoll.find()


得见刚才在主节点插入的数据。这说明数据已经自动从 Primary 复制到了 Secondary。

相关推荐
正在走向自律3 小时前
金仓数据库打通电子证照国产化“最后一公里”——福建某地2TB MongoDB无缝迁移实践
数据库·mongodb·国产数据库·电科金仓
阿波罗尼亚3 小时前
复杂查询:直接查询/子查询/视图/CTE
java·前端·数据库
Go高并发架构_王工3 小时前
MySQL内存优化:缓冲池与查询缓存调优技术详解
数据库·mysql·缓存
disanleya4 小时前
mysql怎么安装,新手安装MySQL后如何安全备份不踩坑?
数据库·mysql
zhennann4 小时前
VonaJS多租户同时支持共享模式和独立模式
数据库·typescript·node.js·nestjs
打码人的日常分享4 小时前
信息化系统安全建设方案
大数据·数据库·人工智能·安全·系统安全
zuoyou-HPU4 小时前
QT中的pyodbc.connect()函数
服务器·数据库·oracle
last_zhiyin4 小时前
Oracle sql tuning guide 翻译 Part 6-3 --- 用Hint影响优化器
数据库·sql·oracle·优化器·hint
静若繁花_jingjing4 小时前
数据库连接池原理
数据库·oracle