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。

相关推荐
胖头鱼的鱼缸(尹海文)7 小时前
数据库管理-第376期 Oracle AI DB 23.26新特性一览(20251016)
数据库·人工智能·oracle
麦聪聊数据7 小时前
浅谈SQL审核(一):SQL审核实现方式与常见工具的选择
数据库·sql
ajassi20007 小时前
开源 Linux 服务器与中间件(七)数据库--MySQL
linux·服务器·数据库·ubuntu·开源
韩立学长7 小时前
【开题答辩实录分享】以《自然灾害隐患点管理信息系统》为例进行答辩实录分享
数据库·spring boot
迎風吹頭髮7 小时前
Linux服务器编程实践58-getnameinfo函数:通过socket地址获取主机名与服务名
开发语言·数据库·php
christine-rr8 小时前
linux常用命令——其他
linux·服务器·网络·数据库·redis·ubuntu
一只专注api接口开发的技术猿8 小时前
容器化与调度:使用 Docker 与 K8s 管理分布式淘宝商品数据采集任务
开发语言·前端·数据库
tryxr8 小时前
MySQL 之索引为什么选择B+树
数据库·mysql·b+树·索引
曦樂~9 小时前
【Qt】信号与槽(Signal and Slot)- 简易计算器
开发语言·数据库·qt
ZYMFZ9 小时前
python面向对象
前端·数据库·python