MongoDB-2 副本集

MongoDB 副本集(Replica Set)详解

  • 副本集是 MongoDB 提供的数据冗余和高可用性解决方案,由一组维护相同数据集的 mongod 实例组成。副本集包含多个数据承载节点和一个可选的仲裁节点。

  • 副本集的优势
    高可用性:自动故障转移,减少停机时间
    数据安全:多副本存储,防止单点故障
    读写分离:分散读取负载
    维护友好:允许无停机维护
    灾难恢复:延迟节点可用于恢复误操作

  • 最佳实践
    副本集至少应有3个数据承载成员
    将成员分布在不同的物理位置(数据中心)
    使用奇数个投票成员(或添加仲裁节点)
    监控复制延迟(rs.printSlaveReplicationInfo)
    定期测试故障转移过程

  • 注意事项
    副本集需要至少3个成员才能实现自动故障转移
    写操作需要"大多数"成员确认(w: "majority")
    网络分区可能导致脑裂情况
    重新配置副本集可能导致短暂的选举过程

副本集的组成

一个典型的 MongoDB 副本集包含以下成员:

  • 主节点(Primary):

    • 接收所有写操作
    • 记录操作日志(oplog)
    • 一个副本集只能有一个主节点
  • 从节点(Secondary):

    • 复制主节点的数据
    • 可以配置为只读或特殊用途(如报表节点)
    • 可以成为新的主节点(故障转移时)
  • 仲裁节点(Arbiter)(可选):

    • 不存储数据
    • 仅参与选举投票
    • 用于解决选举中的平票情况

副本集的工作原理

  1. 数据同步机制
    副本集通过 oplog(操作日志) 实现数据同步:
    主节点记录所有改变数据集的操作到 oplog
    从节点异步复制并应用这些操作
    每个成员都会维护自己的 oplog 副本

  2. 自动故障转移
    当主节点不可用时(超过 electionTimeoutMillis,默认10秒):
    剩余成员发起选举
    获得大多数投票的从节点成为新主节点
    客户端驱动会自动检测并路由写操作到新主节点

  3. 读写一致性
    写操作:默认只在主节点执行
    读操作:可配置从从节点读取(最终一致性)

实现副本集

在三台机器上分别安装mongodb

mongo01 192.168.40.31:27017
mongo02 192.168.40.32:27017
mongo03 192.168.40.33:27017

修改mongodb配置文件

以mongo01为例子,其他两个节点只改IP

net:
  port: 27017
  bindIp: 192.168.40.31
replication:
  replSetName: rs1        # 集群名称,三台机器设置一致
sharding:
  clusterRole: shardsvr   # 集群角色名称,分片
完整配置
# mongod.conf

# for documentation of all options, see:
#   http://docs.mongodb.org/manual/reference/configuration-options/

# Where and how to store data.
storage:
  dbPath: /var/lib/mongodb
#  engine:
#  wiredTiger:

# where to write logging data.
systemLog:
  destination: file
  logAppend: true
  path: /var/log/mongodb/mongod.log

# network interfaces
net:
  port: 27017
  bindIp: 192.168.40.31

# how the process runs
processManagement:
  timeZoneInfo: /usr/share/zoneinfo

#security:

#operationProfiling:

replication:
  replSetName: rs1
sharding:
  clusterRole: shardsvr
## Enterprise-Only Options:

#auditLog:

启动三台mongod服务

systemctl start mongod

连接到一个节点

mongosh --host mongo01:27017

使用默认参数初始化副本集的一个节点(会成为主节点)

rs.initiate()

添加从节点

rs.add("mongo02:27017")

添加仲裁节点

rs.addArb("mongo03:27017")

管理副本集

查看副本集信息

rs.conf()                      // 查看副本集配置信息
rs.status()                    // 查看副本集状态信息
查看副本集配置信息
rs1 [direct: primary] test> rs.conf()
{
  _id: 'rs1',
  version: 6,
  term: 5,
  members: [
    {
      _id: 0,
      host: '192.168.40.31:27017',
      arbiterOnly: false,
      buildIndexes: true,
      hidden: false,
      priority: 1,
      tags: {},
      secondaryDelaySecs: Long('0'),
      votes: 1
    },
    {
      _id: 1,
      host: 'mongo02:27017',
      arbiterOnly: false,
      buildIndexes: true,
      hidden: false,
      priority: 1,
      tags: {},
      secondaryDelaySecs: Long('0'),
      votes: 1
    },
    {
      _id: 2,
      host: 'mongo03:27017',
      arbiterOnly: true,
      buildIndexes: true,
      hidden: false,
      priority: 0,
      tags: {},
      secondaryDelaySecs: Long('0'),
      votes: 1
    }
  ],
  protocolVersion: Long('1'),
  writeConcernMajorityJournalDefault: true,
  settings: {
    chainingAllowed: true,
    heartbeatIntervalMillis: 2000,
    heartbeatTimeoutSecs: 10,
    electionTimeoutMillis: 10000,
    catchUpTimeoutMillis: -1,
    catchUpTakeoverDelayMillis: 30000,
    getLastErrorModes: {},
    getLastErrorDefaults: { w: 1, wtimeout: 0 },
    replicaSetId: ObjectId('696851b2f99f992953d87345')
  }
}

查看副本集状态信息
rs1 [direct: primary] test> rs.status()
{
  set: 'rs1',
  date: ISODate('2026-01-16T10:16:42.484Z'),
  myState: 1,
  term: Long('5'),
  syncSourceHost: '',
  syncSourceId: -1,
  heartbeatIntervalMillis: Long('2000'),
  majorityVoteCount: 2,
  writeMajorityCount: 2,
  votingMembersCount: 3,
  writableVotingMembersCount: 2,
  optimes: {
    lastCommittedOpTime: { ts: Timestamp({ t: 1768558597, i: 1 }), t: Long('5') },
    lastCommittedWallTime: ISODate('2026-01-16T10:16:37.310Z'),
    readConcernMajorityOpTime: { ts: Timestamp({ t: 1768558597, i: 1 }), t: Long('5') },
    appliedOpTime: { ts: Timestamp({ t: 1768558597, i: 1 }), t: Long('5') },
    durableOpTime: { ts: Timestamp({ t: 1768558597, i: 1 }), t: Long('5') },
    lastAppliedWallTime: ISODate('2026-01-16T10:16:37.310Z'),
    lastDurableWallTime: ISODate('2026-01-16T10:16:37.310Z')
  },
  lastStableRecoveryTimestamp: Timestamp({ t: 1768558577, i: 1 }),
  electionCandidateMetrics: {
    lastElectionReason: 'stepUpRequestSkipDryRun',
    lastElectionDate: ISODate('2026-01-16T10:14:57.271Z'),
    electionTerm: Long('5'),
    lastCommittedOpTimeAtElection: { ts: Timestamp({ t: 1768558494, i: 1 }), t: Long('4') },
    lastSeenOpTimeAtElection: { ts: Timestamp({ t: 1768558494, i: 1 }), t: Long('4') },
    numVotesNeeded: 2,
    priorityAtElection: 1,
    electionTimeoutMillis: Long('10000'),
    priorPrimaryMemberId: 1,
    numCatchUpOps: Long('0'),
    newTermStartDate: ISODate('2026-01-16T10:14:57.294Z'),
    wMajorityWriteAvailabilityDate: ISODate('2026-01-16T10:14:57.315Z')
  },
  electionParticipantMetrics: {
    votedForCandidate: true,
    electionTerm: Long('4'),
    lastVoteDate: ISODate('2026-01-16T07:32:13.690Z'),
    electionCandidateMemberId: 1,
    voteReason: '',
    lastAppliedOpTimeAtElection: { ts: Timestamp({ t: 1768548438, i: 1 }), t: Long('3') },
    maxAppliedOpTimeInSet: { ts: Timestamp({ t: 1768548438, i: 1 }), t: Long('3') },
    priorityAtElection: 1
  },
  members: [
    {
      _id: 0,
      name: '192.168.40.31:27017',
      health: 1,
      state: 1,
      stateStr: 'PRIMARY',
      uptime: 114629,
      optime: { ts: Timestamp({ t: 1768558597, i: 1 }), t: Long('5') },
      optimeDate: ISODate('2026-01-16T10:16:37.000Z'),
      lastAppliedWallTime: ISODate('2026-01-16T10:16:37.310Z'),
      lastDurableWallTime: ISODate('2026-01-16T10:16:37.310Z'),
      syncSourceHost: '',
      syncSourceId: -1,
      infoMessage: '',
      electionTime: Timestamp({ t: 1768558497, i: 1 }),
      electionDate: ISODate('2026-01-16T10:14:57.000Z'),
      configVersion: 6,
      configTerm: 5,
      self: true,
      lastHeartbeatMessage: ''
    },
    {
      _id: 1,
      name: 'mongo02:27017',
      health: 1,
      state: 2,
      stateStr: 'SECONDARY',
      uptime: 15744,
      optime: { ts: Timestamp({ t: 1768558597, i: 1 }), t: Long('5') },
      optimeDurable: { ts: Timestamp({ t: 1768558597, i: 1 }), t: Long('5') },
      optimeDate: ISODate('2026-01-16T10:16:37.000Z'),
      optimeDurableDate: ISODate('2026-01-16T10:16:37.000Z'),
      lastAppliedWallTime: ISODate('2026-01-16T10:16:37.310Z'),
      lastDurableWallTime: ISODate('2026-01-16T10:16:37.310Z'),
      lastHeartbeat: ISODate('2026-01-16T10:16:42.129Z'),
      lastHeartbeatRecv: ISODate('2026-01-16T10:16:42.094Z'),
      pingMs: Long('0'),
      lastHeartbeatMessage: '',
      syncSourceHost: '192.168.40.31:27017',
      syncSourceId: 0,
      infoMessage: '',
      configVersion: 6,
      configTerm: 5
    },
    {
      _id: 2,
      name: 'mongo03:27017',
      health: 1,
      state: 7,
      stateStr: 'ARBITER',
      uptime: 72,
      lastHeartbeat: ISODate('2026-01-16T10:16:42.130Z'),
      lastHeartbeatRecv: ISODate('2026-01-16T10:16:42.127Z'),
      pingMs: Long('0'),
      lastHeartbeatMessage: '',
      syncSourceHost: '',
      syncSourceId: -1,
      infoMessage: '',
      configVersion: 6,
      configTerm: 5
    }
  ],
  ok: 1,
  '$clusterTime': {
    clusterTime: Timestamp({ t: 1768558597, i: 1 }),
    signature: {
      hash: Binary.createFromBase64('AAAAAAAAAAAAAAAAAAAAAAAAAAA=', 0),
      keyId: Long('0')
    }
  },
  operationTime: Timestamp({ t: 1768558597, i: 1 })
}

初始化副本集

// 使用默认参数初始化副本集
rs.initiate()

//使用配置描述初始化副本集
rs.initiate(
   {
      _id: "rs1",
      members: [
         { _id: 0, host : "mongo01:27017" },
         { _id: 1, host : "mongo02:27017" },
         { _id: 2, host : "mongo03:27017" }
      ]
   }
)

添加节点

# 添加从节点,并指定特定的属性
rs.add(
 {
   _id: <int>,
   host: <string>,               #主机名称(必须)
   arbiterOnly: <boolean>,       #是否为仲裁节点
   buildIndexes: <boolean>,      #是否要创建索引
   hidden: <boolean>,            #是否隐藏
   priority: <number>,           #优先级
   tags: <document>,             #设置读偏好的标签
   secondaryDelaySecs: <int>,    #比主节点延迟多少秒
   votes: <number>               #是否参与投票,有效值是0或1
 },
 arbiterOnly: <boolean>          #是否为仲裁节点
)

# 添加仲裁节点
rs.addArb("mongo03:27017")

示例:

//添加从节点,并指定特定的属性
rs.add( { host: "mongo02:27017", priority: 0 } )

删除节点

rs.remove("mongo03:27017")

选举相关

// 让主节点降级,默认60秒内不参与选举,需要在主节点执行
rs.stepDown()
// 指定“不可参选”时长(单位:秒),比如120秒
rs.stepDown(120)
// 强制降级(忽略次要节点的同步状态,仅应急使用)
rs.stepDown(60, { force: true })

// 在指定时间内不参与主节点选举(单位:秒),比如60秒,可在任意副本集节点(主节点/从节点/仲裁节点)执行
rs.freeze(60)
// 取消节点的选举冻结状态
rs.freeze(0)
// 在冻结期内再次执行,更新冻结时长(比如延长到120秒)
rs.freeze(120)

// 使从节点从指定的节点(主或从节点)同步数据
rs.syncFrom("mongo03:27017")

// 查看节点的同步源是哪个节点
rs.printSecondaryReplicationInfo()

副本集的高级配置

1. 成员优先级(priority)
cfg = rs.conf()
cfg.members[0].priority = 2
cfg.members[1].priority = 1
cfg.members[2].priority = 0.5
rs.reconfig(cfg)
2. 隐藏节点(hidden)
cfg = rs.conf()
cfg.members[2].hidden = true
cfg.members[2].priority = 0
rs.reconfig(cfg)
3. 延迟节点(delayed)
cfg = rs.conf()
cfg.members[2].priority = 0
cfg.members[2].hidden = true
cfg.members[2].slaveDelay = 3600  // 延迟1小时
rs.reconfig(cfg)
posted @ 2026-03-27 11:26  立勋  阅读(13)  评论(0)    收藏  举报