Mongodb副本集

介绍

为了解决Mongodb数据高可用,官方提供了副本集机制,Mongodb副本集至少需要三个节点,其中一个是主节点,负责处理客户端请求,其余的都是从节点,负责复制主节点上的数据,两个从节点中也可以让其中一个节点做仲裁,不存数据。 Mongodb各个节点常见的搭配方式为:一主一从、一主多从。副本集中只有主能写,其余的从只能读。 主节点记录在其上的所有操作oplog,从节点定期轮询主节点获取这些操作,然后对自己的数据副本执行,这些操作,从而保证从节点的数据与主节点一致。

Mongodb副本集结构图如下所示: ../../_images/11.png 当主节点发生故障后,其中一个从节点会成为新的主。 ../../_images/12.png MongoDB副本集在主从复制基础上实现了故障转移的功能,也就是当主节点宕机时,某一台副本节点会自动提升为新主节点。

副本集搭建

详细参考

搭建三台主机并安装mongodb 安装教程

1.定义PATH

vi /etc/profile.d/mongodb.sh ##增加或者修改
export PATH=$PATH:/usr/local/mongodb/bin

source /etc/profile.d/mongodb.sh ##使环境变量生效

2.创建keyfile (副本集各成员之间认证)

openssl rand -base64 20 > /usr/local/mongodb/conf/keyfile 
chmod 400 /usr/local/mongodb/conf/keyfile

3.编辑配置文件

mkdir  /usr/local/mongodb/{conf,logs}
mkdir  -p /data/mongodb
vi /usr/local/mongodb/conf/mongodb.conf  ##添加如下内容,注意有缩进
systemLog:
  #MongoDB发送所有日志输出的目标指定为文件
  destination: file
  #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  path: "/usr/local/mongodb/logs/mongodb.log"
  #当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾
  logAppend: true
storage:
  #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod
  dbPath: "/data/mongodb"
  journal:
    #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
    enabled: true
processManagement:
  #启用在后台运行mongos或mongod进程的守护进程模式。
  fork: true
  #指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  pidFilePath: "/usr/local/mongodb/logs/mongod.pid"
  #从中加载时区数据库的完整路径
  timeZoneInfo: /usr/share/zoneinfo
net:
  #服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
  #bindIpAll: true
  #服务实例绑定的IP,0.0.0.0让所有机器都能连接。
  bindIp: 0.0.0.0
  #bindIp
  #绑定的端口
  port: 27017
# 安全配置
security:
  # 配置密码文件
  keyFile: /usr/local/mongodb/conf/keyfile
replication:
  #副本集的名称
  replSetName: "aming"

4.编辑systemd服务管理脚本

vi  /lib/systemd/system/mongodb.service ##写入如下内容
[Unit]
Description=mongodb
After=network.target remote-fs.target nss-lookup.target

[Service]
User=mongodb
Type=forking
ExecStart=/usr/local/mongodb/bin/mongod --config /usr/local/mongodb/conf/mongodb.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -QUIT
PrivateTmp=true

[Install]
WantedBy=multi-user.target

5.创建用户,修改权限

useradd -s /sbin/nologin  mongodb
chown -R mongodb /data/mongodb  /usr/local/mongodb

6.启动服务

systemctl daemon-reload
systemctl start mongodb
systemctl enable mongodb

7.安装其余节点 将节点1上的mongodb相关文件拷贝到另外两个节点

scp -r /usr/local/mongodb  aminglinux02:/usr/local/
scp -r /usr/local/mongodb  aminglinux03:/usr/local/

scp /lib/systemd/system/mongodb.service aminglinux02:/lib/systemd/system/
scp /lib/systemd/system/mongodb.service aminglinux03:/lib/systemd/system/

其他操作同上

8.节点1上创建用户 编辑配置文件

vi  /usr/local/mongodb/conf/mongodb.conf ##注释掉下面几行
# 安全配置
#security:
  # 配置密码文件
  #keyFile: /usr/local/mongodb/conf/keyfile
#replication:
  #副本集的名称
  #replSetName: "aming"

重启服务

systemctl restart mongodb

用mongosh工具连接mongodb 安装教程

mongosh ip:prot

进到mongodb命令行里面,创建用户

use admin

db.createUser({user:"root",pwd:"aminglinux.com",roles:["root"]})

退出mongodb命令行,继续编辑配置文件,将刚刚注释掉的几行恢复

vi  /usr/local/mongodb/conf/mongodb.conf ##注释掉下面几行
# 安全配置
security:
  # 配置密码文件
  keyFile: /usr/local/mongodb/conf/keyfile
replication:
  #副本集的名称
  replSetName: "aming"

重启服务

systemctl restart mongodb

9.到节点1上初始化副本集

连接mongodb

mongosh ip:prot

认证

use  admin
db.auth("root","aminglinux.com")

副本集初始化

rs.initiate(
   {
      _id: "aming",
      version: 1,
      members: [
         { _id: 0, host : "aminglinux01:27017" },
         { _id: 1, host : "aminglinux02:27017", arbiterOnly: true },
         { _id: 2, host : "aminglinux03:27017" }
      ]
   }
)

查看副本集状态

aming [direct: primary] admin> rs.status()
{
  set: 'aming',
  date: ISODate("2022-10-04T13:27:38.429Z"),
  myState: 1,
  term: Long("1"),
  syncSourceHost: '',
  syncSourceId: -1,
  heartbeatIntervalMillis: Long("2000"),
  majorityVoteCount: 2,
  writeMajorityCount: 2,
  votingMembersCount: 3,
  writableVotingMembersCount: 2,
  optimes: {
    lastCommittedOpTime: { ts: Timestamp({ t: 1664890054, i: 1 }), t: Long("1") },
    lastCommittedWallTime: ISODate("2022-10-04T13:27:34.625Z"),
    readConcernMajorityOpTime: { ts: Timestamp({ t: 1664890054, i: 1 }), t: Long("1") },
    appliedOpTime: { ts: Timestamp({ t: 1664890054, i: 1 }), t: Long("1") },
    durableOpTime: { ts: Timestamp({ t: 1664890054, i: 1 }), t: Long("1") },
    lastAppliedWallTime: ISODate("2022-10-04T13:27:34.625Z"),
    lastDurableWallTime: ISODate("2022-10-04T13:27:34.625Z")
  },
  lastStableRecoveryTimestamp: Timestamp({ t: 1664890004, i: 1 }),
  electionCandidateMetrics: {
    lastElectionReason: 'electionTimeout',
    lastElectionDate: ISODate("2022-10-04T13:15:03.957Z"),
    electionTerm: Long("1"),
    lastCommittedOpTimeAtElection: { ts: Timestamp({ t: 1664889293, i: 1 }), t: Long("-1") },
    lastSeenOpTimeAtElection: { ts: Timestamp({ t: 1664889293, i: 1 }), t: Long("-1") },
    numVotesNeeded: 2,
    priorityAtElection: 1,
    electionTimeoutMillis: Long("10000"),
    numCatchUpOps: Long("0"),
    newTermStartDate: ISODate("2022-10-04T13:15:04.286Z"),
    wMajorityWriteAvailabilityDate: ISODate("2022-10-04T13:15:05.828Z")
  },
  members: [
    {
      _id: 0,
      name: 'aminglinux01:27017',
      health: 1,
      state: 1,
      stateStr: 'PRIMARY',
      uptime: 835,
      optime: { ts: Timestamp({ t: 1664890054, i: 1 }), t: Long("1") },
      optimeDate: ISODate("2022-10-04T13:27:34.000Z"),
      lastAppliedWallTime: ISODate("2022-10-04T13:27:34.625Z"),
      lastDurableWallTime: ISODate("2022-10-04T13:27:34.625Z"),
      syncSourceHost: '',
      syncSourceId: -1,
      infoMessage: '',
      electionTime: Timestamp({ t: 1664889303, i: 1 }),
      electionDate: ISODate("2022-10-04T13:15:03.000Z"),
      configVersion: 1,
      configTerm: 1,
      self: true,
      lastHeartbeatMessage: ''
    },
    {
      _id: 1,
      name: 'aminglinux02:27017',
      health: 1,
      state: 7,
      stateStr: 'ARBITER',
      uptime: 764,
      lastHeartbeat: ISODate("2022-10-04T13:27:38.120Z"),
      lastHeartbeatRecv: ISODate("2022-10-04T13:27:37.485Z"),
      pingMs: Long("2"),
      lastHeartbeatMessage: '',
      syncSourceHost: '',
      syncSourceId: -1,
      infoMessage: '',
      configVersion: 1,
      configTerm: 1
    },
    {
      _id: 2,
      name: 'aminglinux03:27017',
      health: 1,
      state: 2,
      stateStr: 'SECONDARY',
      uptime: 764,
      optime: { ts: Timestamp({ t: 1664890054, i: 1 }), t: Long("1") },
      optimeDurable: { ts: Timestamp({ t: 1664890054, i: 1 }), t: Long("1") },
      optimeDate: ISODate("2022-10-04T13:27:34.000Z"),
      optimeDurableDate: ISODate("2022-10-04T13:27:34.000Z"),
      lastAppliedWallTime: ISODate("2022-10-04T13:27:34.625Z"),
      lastDurableWallTime: ISODate("2022-10-04T13:27:34.625Z"),
      lastHeartbeat: ISODate("2022-10-04T13:27:38.121Z"),
      lastHeartbeatRecv: ISODate("2022-10-04T13:27:37.014Z"),
      pingMs: Long("3"),
      lastHeartbeatMessage: '',
      syncSourceHost: 'aminglinux01:27017',
      syncSourceId: 0,
      infoMessage: '',
      configVersion: 1,
      configTerm: 1
    }
  ],
  ok: 1,
  '$clusterTime': {
    clusterTime: Timestamp({ t: 1664890054, i: 1 }),
    signature: {
      hash: Binary(Buffer.from("387cab53507429b2fa1e5de0d4bdef373f63e6f7", "hex"), 0),
      keyId: Long("7150645112140201989")
    }
  },
  operationTime: Timestamp({ t: 1664890054, i: 1 })
}

10.模拟故障 将节点1上的mongodb服务停掉

systemctl stop mongodb

到节点3上查看副本集状态

mongosh  127.0.0.1

use admin

db.auth("root","aminglinux.com")

rs.status()
{
  set: 'aming',
  date: ISODate("2022-10-09T08:13:37.403Z"),
  myState: 1,
  term: Long("3"),
  syncSourceHost: '',
  syncSourceId: -1,
  heartbeatIntervalMillis: Long("2000"),
  majorityVoteCount: 2,
  writeMajorityCount: 2,
  votingMembersCount: 3,
  writableVotingMembersCount: 2,
  optimes: {
    lastCommittedOpTime: { ts: Timestamp({ t: 1665303208, i: 2 }), t: Long("3") },
    lastCommittedWallTime: ISODate("2022-10-09T08:13:28.672Z"),
    readConcernMajorityOpTime: { ts: Timestamp({ t: 1665303208, i: 2 }), t: Long("3") },
    appliedOpTime: { ts: Timestamp({ t: 1665303208, i: 2 }), t: Long("3") },
    durableOpTime: { ts: Timestamp({ t: 1665303208, i: 2 }), t: Long("3") },
    lastAppliedWallTime: ISODate("2022-10-09T08:13:28.672Z"),
    lastDurableWallTime: ISODate("2022-10-09T08:13:28.672Z")
  },
  lastStableRecoveryTimestamp: Timestamp({ t: 1664890404, i: 1 }),
  electionCandidateMetrics: {
    lastElectionReason: 'electionTimeout',
    lastElectionDate: ISODate("2022-10-09T08:13:28.601Z"),
    electionTerm: Long("3"),
    lastCommittedOpTimeAtElection: { ts: Timestamp({ t: 1664890414, i: 1 }), t: Long("1") },
    lastSeenOpTimeAtElection: { ts: Timestamp({ t: 1664890414, i: 1 }), t: Long("1") },
    numVotesNeeded: 2,
    priorityAtElection: 1,
    electionTimeoutMillis: Long("10000"),
    numCatchUpOps: Long("0"),
    newTermStartDate: ISODate("2022-10-09T08:13:28.672Z"),
    wMajorityWriteAvailabilityDate: ISODate("2022-10-09T08:13:29.698Z")
  },
  electionParticipantMetrics: {
    votedForCandidate: true,
    electionTerm: Long("1"),
    lastVoteDate: ISODate("2022-10-09T07:56:09.459Z"),
    electionCandidateMemberId: 0,
    voteReason: '',
    lastAppliedOpTimeAtElection: { ts: Timestamp({ t: 1664889293, i: 1 }), t: Long("-1") },
    maxAppliedOpTimeInSet: { ts: Timestamp({ t: 1664889293, i: 1 }), t: Long("-1") },
    priorityAtElection: 1
  },
  members: [
    {
      _id: 0,
      name: 'aminglinux01:27017',
      health: 0,
      state: 8,
      stateStr: '(not reachable/healthy)',
      uptime: 0,
      optime: { ts: Timestamp({ t: 0, i: 0 }), t: Long("-1") },
      optimeDurable: { ts: Timestamp({ t: 0, i: 0 }), t: Long("-1") },
      optimeDate: ISODate("1970-01-01T00:00:00.000Z"),
      optimeDurableDate: ISODate("1970-01-01T00:00:00.000Z"),
      lastAppliedWallTime: ISODate("2022-10-09T08:13:28.672Z"),
      lastDurableWallTime: ISODate("2022-10-09T08:13:28.672Z"),
      lastHeartbeat: ISODate("2022-10-09T08:13:36.815Z"),
      lastHeartbeatRecv: ISODate("2022-10-09T08:13:29.686Z"),
      pingMs: Long("1"),
      lastHeartbeatMessage: 'Error connecting to aminglinux01:27017 (192.168.222.128:27017) :: caused by :: Connection refused',
      syncSourceHost: '',
      syncSourceId: -1,
      infoMessage: '',
      configVersion: 1,
      configTerm: 1
    },
    {
      _id: 1,
      name: 'aminglinux02:27017',
      health: 1,
      state: 7,
      stateStr: 'ARBITER',
      uptime: 1057,
      lastHeartbeat: ISODate("2022-10-09T08:13:36.702Z"),
      lastHeartbeatRecv: ISODate("2022-10-09T08:13:36.701Z"),
      pingMs: Long("2"),
      lastHeartbeatMessage: '',
      syncSourceHost: '',
      syncSourceId: -1,
      infoMessage: '',
      configVersion: 1,
      configTerm: 3
    },
    {
      _id: 2,
      name: 'aminglinux03:27017',
      health: 1,
      state: 1,
      stateStr: 'PRIMARY',
      uptime: 2384,
      optime: { ts: Timestamp({ t: 1665303208, i: 2 }), t: Long("3") },
      optimeDate: ISODate("2022-10-09T08:13:28.000Z"),
      lastAppliedWallTime: ISODate("2022-10-09T08:13:28.672Z"),
      lastDurableWallTime: ISODate("2022-10-09T08:13:28.672Z"),
      syncSourceHost: '',
      syncSourceId: -1,
      infoMessage: '',
      electionTime: Timestamp({ t: 1665303208, i: 1 }),
      electionDate: ISODate("2022-10-09T08:13:28.000Z"),
      configVersion: 1,
      configTerm: 3,
      self: true,
      lastHeartbeatMessage: ''
    }
  ],
  ok: 1,
  '$clusterTime': {
    clusterTime: Timestamp({ t: 1665303208, i: 2 }),
    signature: {
      hash: Binary(Buffer.from("dd7df9ea0f127c3deb97a9658053320863968bcc", "hex"), 0),
      keyId: Long("7150645112140201989")
    }
  },
  operationTime: Timestamp({ t: 1665303208, i: 2 })
}

此时节点1,显示无法连接,节点3变成了primary

再次将节点1启动

systemctl start mongodb

节点3上再次查看副本集状态

rs.status()
{
  set: 'aming',
  date: ISODate("2022-10-09T08:15:29.956Z"),
  myState: 1,
  term: Long("3"),
  syncSourceHost: '',
  syncSourceId: -1,
  heartbeatIntervalMillis: Long("2000"),
  majorityVoteCount: 2,
  writeMajorityCount: 2,
  votingMembersCount: 3,
  writableVotingMembersCount: 2,
  optimes: {
    lastCommittedOpTime: { ts: Timestamp({ t: 1665303328, i: 1 }), t: Long("3") },
    lastCommittedWallTime: ISODate("2022-10-09T08:15:28.707Z"),
    readConcernMajorityOpTime: { ts: Timestamp({ t: 1665303328, i: 1 }), t: Long("3") },
    appliedOpTime: { ts: Timestamp({ t: 1665303328, i: 1 }), t: Long("3") },
    durableOpTime: { ts: Timestamp({ t: 1665303328, i: 1 }), t: Long("3") },
    lastAppliedWallTime: ISODate("2022-10-09T08:15:28.707Z"),
    lastDurableWallTime: ISODate("2022-10-09T08:15:28.707Z")
  },
  lastStableRecoveryTimestamp: Timestamp({ t: 1665303208, i: 2 }),
  electionCandidateMetrics: {
    lastElectionReason: 'electionTimeout',
    lastElectionDate: ISODate("2022-10-09T08:13:28.601Z"),
    electionTerm: Long("3"),
    lastCommittedOpTimeAtElection: { ts: Timestamp({ t: 1664890414, i: 1 }), t: Long("1") },
    lastSeenOpTimeAtElection: { ts: Timestamp({ t: 1664890414, i: 1 }), t: Long("1") },
    numVotesNeeded: 2,
    priorityAtElection: 1,
    electionTimeoutMillis: Long("10000"),
    numCatchUpOps: Long("0"),
    newTermStartDate: ISODate("2022-10-09T08:13:28.672Z"),
    wMajorityWriteAvailabilityDate: ISODate("2022-10-09T08:13:29.698Z")
  },
  electionParticipantMetrics: {
    votedForCandidate: true,
    electionTerm: Long("1"),
    lastVoteDate: ISODate("2022-10-09T07:56:09.459Z"),
    electionCandidateMemberId: 0,
    voteReason: '',
    lastAppliedOpTimeAtElection: { ts: Timestamp({ t: 1664889293, i: 1 }), t: Long("-1") },
    maxAppliedOpTimeInSet: { ts: Timestamp({ t: 1664889293, i: 1 }), t: Long("-1") },
    priorityAtElection: 1
  },
  members: [
    {
      _id: 0,
      name: 'aminglinux01:27017',
      health: 1,
      state: 2,
      stateStr: 'SECONDARY',
      uptime: 4,
      optime: { ts: Timestamp({ t: 1665303328, i: 1 }), t: Long("3") },
      optimeDurable: { ts: Timestamp({ t: 1665303328, i: 1 }), t: Long("3") },
      optimeDate: ISODate("2022-10-09T08:15:28.000Z"),
      optimeDurableDate: ISODate("2022-10-09T08:15:28.000Z"),
      lastAppliedWallTime: ISODate("2022-10-09T08:15:28.707Z"),
      lastDurableWallTime: ISODate("2022-10-09T08:15:28.707Z"),
      lastHeartbeat: ISODate("2022-10-09T08:15:29.118Z"),
      lastHeartbeatRecv: ISODate("2022-10-09T08:15:28.271Z"),
      pingMs: Long("1"),
      lastHeartbeatMessage: '',
      syncSourceHost: 'aminglinux03:27017',
      syncSourceId: 2,
      infoMessage: '',
      configVersion: 1,
      configTerm: 3
    },
    {
      _id: 1,
      name: 'aminglinux02:27017',
      health: 1,
      state: 7,
      stateStr: 'ARBITER',
      uptime: 1169,
      lastHeartbeat: ISODate("2022-10-09T08:15:28.843Z"),
      lastHeartbeatRecv: ISODate("2022-10-09T08:15:28.828Z"),
      pingMs: Long("1"),
      lastHeartbeatMessage: '',
      syncSourceHost: '',
      syncSourceId: -1,
      infoMessage: '',
      configVersion: 1,
      configTerm: 3
    },
    {
      _id: 2,
      name: 'aminglinux03:27017',
      health: 1,
      state: 1,
      stateStr: 'PRIMARY',
      uptime: 2496,
      optime: { ts: Timestamp({ t: 1665303328, i: 1 }), t: Long("3") },
      optimeDate: ISODate("2022-10-09T08:15:28.000Z"),
      lastAppliedWallTime: ISODate("2022-10-09T08:15:28.707Z"),
      lastDurableWallTime: ISODate("2022-10-09T08:15:28.707Z"),
      syncSourceHost: '',
      syncSourceId: -1,
      infoMessage: '',
      electionTime: Timestamp({ t: 1665303208, i: 1 }),
      electionDate: ISODate("2022-10-09T08:13:28.000Z"),
      configVersion: 1,
      configTerm: 3,
      self: true,
      lastHeartbeatMessage: ''
    }
  ],
  ok: 1,
  '$clusterTime': {
    clusterTime: Timestamp({ t: 1665303328, i: 1 }),
    signature: {
      hash: Binary(Buffer.from("79f96888b9567f3f1be25b3436a206fc59c31519", "hex"), 0),
      keyId: Long("7150645112140201989")
    }
  },
  operationTime: Timestamp({ t: 1665303328, i: 1 })
}

节点1上线,变为secondary