HOPES

MongoDBのレプリカセットの設定

MongoDBのレプリカセットの設定

MongoDBで、データの可用性を高めるためのレプリカセットの設定についてまとめています。

MongoDBのレプリカセットについて

MongoDBのレプリカセットについては、公式のドキュメントに詳細な説明があります。

A replica set in MongoDB is a group of mongod processes that maintain the same data set. Replica sets provide redundancy and high availability, and are the basis for all production deployments. This section introduces replication in MongoDB as well as the components and architecture of replica sets.

Replication — MongoDB Manual

以下に特に重要な特徴な部分を抜粋してまとめています。

レプリカセットの概要

レプリカセットは、他のデータベースでいうレプリケーションの仕組みのことで、冗長性を実現し、データの可用性を高めます。

Replication provides redundancy and increases data availability. With multiple copies of data on different database servers, replication provides a level of fault tolerance against the loss of a single database server.

Replication — MongoDB Manual

レプリカセットのグループの中で、プライマリーノードは、1台だけであり、プライマリーノードは、すべての書き込み操作を受け取ります。

A replica set is a group of mongod instances that maintain the same data set. A replica set contains several data bearing nodes and optionally one arbiter node. Of the data bearing nodes, one and only one member is deemed the primary node, while the other nodes are deemed secondary nodes.

Replication — MongoDB Manual

セカンダリーノードは、プライマリーノードのデータを非同期でコピーすることで、プライマリーと同じデータを保持します。

The secondaries replicate the primary's oplog and apply the operations to their data sets such that the secondaries' data sets reflect the primary's data set.

Replication — MongoDB Manual

自動フェイルオーバー機能が備わっており、プライマリーノードに障害が発生した場合でも、投票により、セカンダリーノードがプライマリーノードに昇格することで、システムの稼働を続けるようになっています。

When a primary does not communicate with the other members of the set for more than the configured electionTimeoutMillis period (10 seconds by default), an eligible secondary calls for an election to nominate itself as the new primary. The cluster attempts to complete the election of a new primary and resume normal operations.

Replication — MongoDB Manual

レプリカセットの最小推奨構成として、3台のサーバが必要で、1つのPrimary、と2つのSecondaryで構成されます。ただし、2つのSecondaryのうちひとつは、投票券だけをもち、データは保持しないarbiterにすることも可能です。

The minimum recommended configuration for a replica set is a three member replica set with three data-bearing members: one primary and two secondary members. In some circumstances (such as you have a primary and a secondary but cost constraints prohibit adding another secondary), you may choose to include an arbiter. An arbiter participates in elections but does not hold data (i.e. does not provide data redundancy).

Replica Set Members — MongoDB Manual


MongoDBのレプリカセットの設定と初期化

それでは、レプリカセットを構成するようサーバを設定していきます。
まずは、3台のサーバで、MongoDBのインストールを完了します。
ここでは、「10.0.0.11」、「10.0.0.12」、「10.0.0.13」のサーバにそれぞれMongoDBをインストールしました。

通信の設定

MongoDBの設定ファイルを編集して、「bindIp: 0.0.0.」と設定し、リモートからのアクセスを有効にします。

# vi /etc/mongod.conf
# network interfaces
net:
  port: 27017
  bindIp: 0.0.0.0  # Enter 0.0.0.0,:: to bind to all IPv4 and IPv6 addresses or, alternatively, use the net.bindIpAll setting.

ファイアウォールを設定します。ここでは、ローカルネットワーク内の27017ポートで通信できるようにします。

# firewall-cmd --permanent --new-zone=local
# firewall-cmd --permanent --zone=local --set-target=ACCEPT
# firewall-cmd --permanent --zone=local --add-source=10.0.0.0/24
# firewall-cmd --permanent --zone=local --add-port=22017/tcp
# firewall-cmd --reload

レプリカセット項目の設定

MongoDBの設定ファイルを編集して、レプリカセットの項目を追記して設定します。

replication Options

replication:

oplogSizeMB: int

replSetName: string

enableMajorityReadConcern: boolean

Configuration File Options — MongoDB Manual

「oplogSizeMB」のデフォルトは、WiredTigerストレージエンジンの場合、空きディスク容量の5%となっています。

When you start a replica set member for the first time, MongoDB creates an oplog of a default size if you do not specify the oplog size.

Replica Set Oplog — MongoDB Manual

ここでは、「replSetName」をrplに、「oplogSizeMB」を8Gに設定します。

# vi /etc/mongod.conf
replication:
   oplogSizeMB: 8192
   replSetName: "rpl"

再起動して設定を反映させます。

# systemctl restart mongod

レプリカセットの初期化

「10.0.0.11」のサーバにアクセスします。

# mongosh 10.0.0.11:27017

レプリカセットの初期化処理を実行します。

> rs.initiate({
    _id : "rpl",
    members: [
       { _id: 0, host: "10.0.0.11:27017" },
       { _id: 1, host: "10.0.0.12:27017" },
       { _id: 2, host: "10.0.0.13:27017" },
    ]
 })
{ ok: 1 }

レプリカセットの動作確認

レプリカセットの設定を確認します。

rpl [direct: other] test> rs.conf()
{
  _id: 'rpl',
  version: 1,
  term: 1,
  members: [
    {
      _id: 0,
      host: '10.0.0.11:27017',
      arbiterOnly: false,
      buildIndexes: true,
      hidden: false,
      priority: 1,
      tags: {},
      secondaryDelaySecs: Long("0"),
      votes: 1
    },
    {
      _id: 1,
      host: '10.0.0.12:27017',
      arbiterOnly: false,
      buildIndexes: true,
      hidden: false,
      priority: 1,
      tags: {},
      secondaryDelaySecs: Long("0"),
      votes: 1
    },
    {
      _id: 2,
      host: '10.0.0.13:27017',
      arbiterOnly: false,
      buildIndexes: true,
      hidden: false,
      priority: 1,
      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("62f4bd95dfc3830c0908ddbe")
  }
}

レプリカセットのステータスを確認します。

rpl [direct: primary] test> rs.status()
{
  set: 'rpl',
  date: ISODate("2022-08-11T08:52:45.822Z"),
  myState: 1,
  term: Long("1"),
  syncSourceHost: '',
  syncSourceId: -1,
  heartbeatIntervalMillis: Long("2000"),
  majorityVoteCount: 2,
  writeMajorityCount: 2,
  votingMembersCount: 3,
  writableVotingMembersCount: 3,
  optimes: {
    lastCommittedOpTime: { ts: Timestamp({ t: 1660207957, i: 1 }), t: Long("1") },
    lastCommittedWallTime: ISODate("2022-08-11T08:52:37.096Z"),
    readConcernMajorityOpTime: { ts: Timestamp({ t: 1660207957, i: 1 }), t: Long("1") },
    appliedOpTime: { ts: Timestamp({ t: 1660207957, i: 1 }), t: Long("1") },
    durableOpTime: { ts: Timestamp({ t: 1660207957, i: 1 }), t: Long("1") },
    lastAppliedWallTime: ISODate("2022-08-11T08:52:37.096Z"),
    lastDurableWallTime: ISODate("2022-08-11T08:52:37.096Z")
  },
  lastStableRecoveryTimestamp: Timestamp({ t: 1660207917, i: 1 }),
  electionCandidateMetrics: {
    lastElectionReason: 'electionTimeout',
    lastElectionDate: ISODate("2022-08-11T08:28:16.995Z"),
    electionTerm: Long("1"),
    lastCommittedOpTimeAtElection: { ts: Timestamp({ t: 1660206485, i: 1 }), t: Long("-1") },
    lastSeenOpTimeAtElection: { ts: Timestamp({ t: 1660206485, i: 1 }), t: Long("-1") },
    numVotesNeeded: 2,
    priorityAtElection: 1,
    electionTimeoutMillis: Long("10000"),
    numCatchUpOps: Long("0"),
    newTermStartDate: ISODate("2022-08-11T08:28:17.009Z"),
    wMajorityWriteAvailabilityDate: ISODate("2022-08-11T08:28:18.054Z")
  },
  members: [
    {
      _id: 0,
      name: '10.0.0.11:27017',
      health: 1,
      state: 1,
      stateStr: 'PRIMARY',
      uptime: 2353,
      optime: { ts: Timestamp({ t: 1660207957, i: 1 }), t: Long("1") },
      optimeDate: ISODate("2022-08-11T08:52:37.000Z"),
      lastAppliedWallTime: ISODate("2022-08-11T08:52:37.096Z"),
      lastDurableWallTime: ISODate("2022-08-11T08:52:37.096Z"),
      syncSourceHost: '',
      syncSourceId: -1,
      infoMessage: '',
      electionTime: Timestamp({ t: 1660206496, i: 1 }),
      electionDate: ISODate("2022-08-11T08:28:16.000Z"),
      configVersion: 1,
      configTerm: 1,
      self: true,
      lastHeartbeatMessage: ''
    },
    {
      _id: 1,
      name: '10.0.0.12:27017',
      health: 1,
      state: 2,
      stateStr: 'SECONDARY',
      uptime: 1480,
      optime: { ts: Timestamp({ t: 1660207957, i: 1 }), t: Long("1") },
      optimeDurable: { ts: Timestamp({ t: 1660207957, i: 1 }), t: Long("1") },
      optimeDate: ISODate("2022-08-11T08:52:37.000Z"),
      optimeDurableDate: ISODate("2022-08-11T08:52:37.000Z"),
      lastAppliedWallTime: ISODate("2022-08-11T08:52:37.096Z"),
      lastDurableWallTime: ISODate("2022-08-11T08:52:37.096Z"),
      lastHeartbeat: ISODate("2022-08-11T08:52:45.001Z"),
      lastHeartbeatRecv: ISODate("2022-08-11T08:52:45.076Z"),
      pingMs: Long("0"),
      lastHeartbeatMessage: '',
      syncSourceHost: '10.0.0.11:27017',
      syncSourceId: 0,
      infoMessage: '',
      configVersion: 1,
      configTerm: 1
    },
    {
      _id: 2,
      name: '10.0.0.13:27017',
      health: 1,
      state: 2,
      stateStr: 'SECONDARY',
      uptime: 1480,
      optime: { ts: Timestamp({ t: 1660207957, i: 1 }), t: Long("1") },
      optimeDurable: { ts: Timestamp({ t: 1660207957, i: 1 }), t: Long("1") },
      optimeDate: ISODate("2022-08-11T08:52:37.000Z"),
      optimeDurableDate: ISODate("2022-08-11T08:52:37.000Z"),
      lastAppliedWallTime: ISODate("2022-08-11T08:52:37.096Z"),
      lastDurableWallTime: ISODate("2022-08-11T08:52:37.096Z"),
      lastHeartbeat: ISODate("2022-08-11T08:52:45.001Z"),
      lastHeartbeatRecv: ISODate("2022-08-11T08:52:45.001Z"),
      pingMs: Long("0"),
      lastHeartbeatMessage: '',
      syncSourceHost: '10.0.0.11:27017',
      syncSourceId: 0,
      infoMessage: '',
      configVersion: 1,
      configTerm: 1
    }
  ],
  ok: 1,
  '$clusterTime': {
    clusterTime: Timestamp({ t: 1660207957, i: 1 }),
    signature: {
      hash: Binary(Buffer.from("0000000000000000000000000000000000000000", "hex"), 0),
      keyId: Long("0")
    }
  },
  operationTime: Timestamp({ t: 1660207957, i: 1 })
}

PrimaryとSecondaryへのアクセスについて

MongoDBの操作は、基本的にPrimaryからしか操作できません。mongoシェルでアクセスすると、「Primary」にアクセスしているのか、「Secondary」にアクセスしているのかを表示してくれます。

「10.0.0.11」へアクセスした場合、

# mongosh 10.0.0.11:27017
rpl [direct: primary] test> 

「10.0.0.12」へアクセスした場合、

# mongosh 10.0.0.12:27017
rpl [direct: secondary] test> 

となっています。

以上で、レプリカセットの設定については完了です。

2022年08月12日に投稿されました。