MongoDB 监控(十)MongoDB 副本集集群搭建及获取副本集状态

快猫实习生 2024-11-18 17:31:24

MongoDB 监控

这是 MongoDB 监控系列文章的第十篇,前面几篇文章的链接如下:

之前的章节我们重点研究的是 MongoDB 单节点模式,这一节我们探索一下 MongoDB 的副本集集群以及相关的监控命令。MongoDB 的副本集集群有点像是 MySQL 的一主多从的方式,具备高可用能力,但是不具备水平扩展能力,如果想要水平扩展能力,则需要使用分片集群。多个副本集集群组成一套分片集群。

MongoDB 副本集集群搭建

参考:https://www.cnblogs.com/studyjobs/p/17643808.html

我们使用 docker compose 快速启动一个 MongoDB 副本集集群,首先创建三个目录,存放三个 MongoDB 实例的数据:

mkdir -p /Users/ulric/works/mongos/mongo1
mkdir -p /Users/ulric/works/mongos/mongo2
mkdir -p /Users/ulric/works/mongos/mongo3

mongodb 使用 keyFile 进行认证,副本集群中的每个节点的 mongodb 使用 keyFile 的内容作为认证其他成员的共享密码。mongodb 实例只有拥有正确的 keyFile 才可以加入副本集群,集群中所有成员的 keyFile 内容必须相同。

cd /Users/ulric/works/mongos
openssl rand -base64 666 > mongodb.key

mongodb 的集群其实有 3 种角色:主节点、从节点、仲裁节点(可选,可有可无)

  • 主节点(Primary):主要负责数据的写操作,当然也可以读取数据,大部分命令需要在主节点才能运行。
  • 从节点(Secondary):从主节点实时同步数据,只能读取数据,不能进行写操作。
  • 仲裁节点(Arbiter):不保留任何数据的副本,只能用来投票选举使用。

本篇博客的演示中,没有去设置仲裁节点,3 个节点都保留数据副本。在 /Users/ulric/works/mongos 目录下创建 docker-compose.yml 文件:

services:
  # 服务名称
  mongodb1:
    # 使用最新的 mongodb 镜像
    image: mongo:latest
    # docker 服务启动时,自动启动 mongo 容器
    restart: always
    # 容器的名称
    container_name: mongo1
    # 宿主机中的目录和文件,映射容器内部的目录和文件
    volumes:
      - /Users/ulric/works/mongos/mongo1:/data/db
      - /Users/ulric/works/mongos/mongodb.key:/data/mongodb.key
    ports:
      # 宿主机的端口映射容器内的端口
      - 27017:27017
    environment:
      # 初始化一个 root 角色的用户 jobs 密码是 123456
      - MONGO_INITDB_ROOT_USERNAME=jobs
      - MONGO_INITDB_ROOT_PASSWORD=123456
    # 使用创建的桥接网络,把各个 mongodb 容器连接在一起
    networks:
      - mongoNetwork
    # 启动容器时,在容器内部额外执行的命令
    # 其中 --replSet 参数后面的 mongos 是集群名称,这个很重要
    command: mongod --replSet mongos --keyFile /data/mongodb.key
    entrypoint:
      - bash
      - -c
      - |
        chmod 400 /data/mongodb.key
        chown 999:999 /data/mongodb.key
        exec docker-entrypoint.sh $$@        
  
  mongodb2:
    image: mongo:latest
    restart: always
    container_name: mongo2
    volumes:
      - /Users/ulric/works/mongos/mongo2:/data/db
      - /Users/ulric/works/mongos/mongodb.key:/data/mongodb.key
    ports:
      - 27018:27017
    environment:
      - MONGO_INITDB_ROOT_USERNAME=jobs
      - MONGO_INITDB_ROOT_PASSWORD=123456
    networks:
      - mongoNetwork
    command: mongod --replSet mongos --keyFile /data/mongodb.key
    entrypoint:
      - bash
      - -c
      - |
        chmod 400 /data/mongodb.key
        chown 999:999 /data/mongodb.key
        exec docker-entrypoint.sh $$@        
 
  mongodb3:
    image: mongo:latest
    restart: always
    container_name: mongo3
    volumes:
      - /Users/ulric/works/mongos/mongo3:/data/db
      - /Users/ulric/works/mongos/mongodb.key:/data/mongodb.key
    ports:
      - 27019:27017
    environment:
      - MONGO_INITDB_ROOT_USERNAME=jobs
      - MONGO_INITDB_ROOT_PASSWORD=123456
    networks:
      - mongoNetwork
    command: mongod --replSet mongos --keyFile /data/mongodb.key
    entrypoint:
      - bash
      - -c
      - |
        chmod 400 /data/mongodb.key
        chown 999:999 /data/mongodb.key
        exec docker-entrypoint.sh $$@        
 
# 创建一个桥接网络,把各个 mongodb 实例连接在一起,该网络适用于单机
# 如果在不同的宿主机上,使用 docker swarm 需要创建 overlay 网络
networks:
  mongoNetwork:
    driver: bridge

然后执行 docker compose up -d 启动 MongoDB 副本集集群,启动后可以通过 docker ps 查看容器是否启动成功。

随便进入其中一个容器,比如进入 mongo1 docker exec -it mongo1 bash,然后进入 mongo 客户端 mongosh -u jobs -p 123456,执行以下命令配置将 3 个节点初始化为一个副本集群:

rs.initiate({
    _id: "mongos",
    members: [
        { _id : 0, host : "10.211.55.2:27017" },
        { _id : 1, host : "10.211.55.2:27018" },
        { _id : 2, host : "10.211.55.2:27019" }
    ]
});

初始化完成之后,通过 rs.status() 命令可以看到副本集集群的状态:

mongos [direct: primary] test> use admin
switched to db admin
mongos [direct: primary] admin> rs.status()
{
  set: 'mongos',
  date: ISODate('2024-11-18T09:39:48.651Z'),
  myState: 1,
  term: Long('1'),
  syncSourceHost: '',
  syncSourceId: -1,
  heartbeatIntervalMillis: Long('2000'),
  majorityVoteCount: 2,
  writeMajorityCount: 2,
  votingMembersCount: 3,
  writableVotingMembersCount: 3,
  optimes: {
    lastCommittedOpTime: { ts: Timestamp({ t: 1731922780, i: 1 }), t: Long('1') },
    lastCommittedWallTime: ISODate('2024-11-18T09:39:40.165Z'),
    readConcernMajorityOpTime: { ts: Timestamp({ t: 1731922780, i: 1 }), t: Long('1') },
    appliedOpTime: { ts: Timestamp({ t: 1731922780, i: 1 }), t: Long('1') },
    durableOpTime: { ts: Timestamp({ t: 1731922780, i: 1 }), t: Long('1') },
    writtenOpTime: { ts: Timestamp({ t: 1731922780, i: 1 }), t: Long('1') },
    lastAppliedWallTime: ISODate('2024-11-18T09:39:40.165Z'),
    lastDurableWallTime: ISODate('2024-11-18T09:39:40.165Z'),
    lastWrittenWallTime: ISODate('2024-11-18T09:39:40.165Z')
  },
  lastStableRecoveryTimestamp: Timestamp({ t: 1731922730, i: 1 }),
  electionCandidateMetrics: {
    lastElectionReason: 'electionTimeout',
    lastElectionDate: ISODate('2024-11-18T08:21:08.285Z'),
    electionTerm: Long('1'),
    lastCommittedOpTimeAtElection: { ts: Timestamp({ t: 1731918057, i: 1 }), t: Long('-1') },
    lastSeenWrittenOpTimeAtElection: { ts: Timestamp({ t: 1731918057, i: 1 }), t: Long('-1') },
    lastSeenOpTimeAtElection: { ts: Timestamp({ t: 1731918057, i: 1 }), t: Long('-1') },
    numVotesNeeded: 2,
    priorityAtElection: 1,
    electionTimeoutMillis: Long('10000'),
    numCatchUpOps: Long('0'),
    newTermStartDate: ISODate('2024-11-18T08:21:08.329Z'),
    wMajorityWriteAvailabilityDate: ISODate('2024-11-18T08:21:08.820Z')
  },
  members: [
    {
      _id: 0,
      name: '10.211.55.2:27017',
      health: 1,
      state: 1,
      stateStr: 'PRIMARY',
      uptime: 5067,
      optime: { ts: Timestamp({ t: 1731922780, i: 1 }), t: Long('1') },
      optimeDate: ISODate('2024-11-18T09:39:40.000Z'),
      optimeWritten: { ts: Timestamp({ t: 1731922780, i: 1 }), t: Long('1') },
      optimeWrittenDate: ISODate('2024-11-18T09:39:40.000Z'),
      lastAppliedWallTime: ISODate('2024-11-18T09:39:40.165Z'),
      lastDurableWallTime: ISODate('2024-11-18T09:39:40.165Z'),
      lastWrittenWallTime: ISODate('2024-11-18T09:39:40.165Z'),
      syncSourceHost: '',
      syncSourceId: -1,
      infoMessage: '',
      electionTime: Timestamp({ t: 1731918068, i: 1 }),
      electionDate: ISODate('2024-11-18T08:21:08.000Z'),
      configVersion: 1,
      configTerm: 1,
      self: true,
      lastHeartbeatMessage: ''
    },
    {
      _id: 1,
      name: '10.211.55.2:27018',
      health: 1,
      state: 2,
      stateStr: 'SECONDARY',
      uptime: 4731,
      optime: { ts: Timestamp({ t: 1731922780, i: 1 }), t: Long('1') },
      optimeDurable: { ts: Timestamp({ t: 1731922780, i: 1 }), t: Long('1') },
      optimeWritten: { ts: Timestamp({ t: 1731922780, i: 1 }), t: Long('1') },
      optimeDate: ISODate('2024-11-18T09:39:40.000Z'),
      optimeDurableDate: ISODate('2024-11-18T09:39:40.000Z'),
      optimeWrittenDate: ISODate('2024-11-18T09:39:40.000Z'),
      lastAppliedWallTime: ISODate('2024-11-18T09:39:40.165Z'),
      lastDurableWallTime: ISODate('2024-11-18T09:39:40.165Z'),
      lastWrittenWallTime: ISODate('2024-11-18T09:39:40.165Z'),
      lastHeartbeat: ISODate('2024-11-18T09:39:47.018Z'),
      lastHeartbeatRecv: ISODate('2024-11-18T09:39:47.014Z'),
      pingMs: Long('0'),
      lastHeartbeatMessage: '',
      syncSourceHost: '10.211.55.2:27017',
      syncSourceId: 0,
      infoMessage: '',
      configVersion: 1,
      configTerm: 1
    },
    {
      _id: 2,
      name: '10.211.55.2:27019',
      health: 1,
      state: 2,
      stateStr: 'SECONDARY',
      uptime: 4731,
      optime: { ts: Timestamp({ t: 1731922780, i: 1 }), t: Long('1') },
      optimeDurable: { ts: Timestamp({ t: 1731922780, i: 1 }), t: Long('1') },
      optimeWritten: { ts: Timestamp({ t: 1731922780, i: 1 }), t: Long('1') },
      optimeDate: ISODate('2024-11-18T09:39:40.000Z'),
      optimeDurableDate: ISODate('2024-11-18T09:39:40.000Z'),
      optimeWrittenDate: ISODate('2024-11-18T09:39:40.000Z'),
      lastAppliedWallTime: ISODate('2024-11-18T09:39:40.165Z'),
      lastDurableWallTime: ISODate('2024-11-18T09:39:40.165Z'),
      lastWrittenWallTime: ISODate('2024-11-18T09:39:40.165Z'),
      lastHeartbeat: ISODate('2024-11-18T09:39:47.018Z'),
      lastHeartbeatRecv: ISODate('2024-11-18T09:39:47.013Z'),
      pingMs: Long('0'),
      lastHeartbeatMessage: '',
      syncSourceHost: '10.211.55.2:27017',
      syncSourceId: 0,
      infoMessage: '',
      configVersion: 1,
      configTerm: 1
    }
  ],
  ok: 1,
  '$clusterTime': {
    clusterTime: Timestamp({ t: 1731922780, i: 1 }),
    signature: {
      hash: Binary.createFromBase64('pGZHCVLcTS6roDiQL8DsOUTkKD0=', 0),
      keyId: Long('7438531461411504133')
    }
  },
  operationTime: Timestamp({ t: 1731922780, i: 1 })
}

通过上面的输出可以看到,三个实例,其中一个是主节点,两个是从节点,这样就搭建了一个 MongoDB 副本集集群。每个实例都有很多字段,比如 health、state、uptime、optime、lastHeartbeat 等等,正常的集群,三个节点的 optimeDate 应该是类似的。一般监控数据采集器 agent 会采集 MongoDB 的副本集信息,通常执行的是 db.runCommand({replSetGetStatus: 1}) 命令,和 rs.status() 命令效果一样。

联系我们交流

快猫星云 联系方式 快猫星云 联系方式
快猫星云 联系方式
快猫星云 联系方式
快猫星云 联系方式
快猫星云
OpenSource
开源版
Flashcat
Flashcat