🙌

Docker Compose で MongoDB のレプリカセットを構築してみた

2025/02/21に公開

MongoDB のレプリカセットとは?

Gemini に聞いてみた

MongoDB のレプリカセットとは、データの冗長性と高可用性を提供する機能です。複数の MongoDB サーバー(ノード)で構築され、同一のデータセットを保持します。これにより、ハードウェア障害やネットワーク障害が発生した場合でも、データへのアクセスを継続できます。

レプリカセットの主な特徴

  • データの冗長性
    複数のノードが同一のデータを保持するため、1つまたは複数のノードが故障してもデータは失われない。
  • 高可用性
    Primary ノードがダウンした場合、自動的に Secondary ノードが Primary ノードに昇格し、サービスを継続する。
  • 自動フェイルオーバー
    Primary ノードの障害を検知し、自動的に新しい Primary ノードを選出する機能がある。
  • 読み込みスケーラビリティ
    Secondary ノードから読み込みを行うことで、読み込み処理を分散しパフォーマンスを向上させることができる。

レプリカセットの構成要素

  • Primary ノード
    • レプリカセットの中で唯一書き込みを受け付けるノード。
    • 全ての書き込み操作は Primary ノードに集中し、そこから他の Secondary ノードにデータが複製される。
    • クライアントからの読み込み要求も Primary ノードで処理されるが、設定によっては Secondary ノードからの読み込みも可能。
    • Primary ノードがダウンした場合、レプリカセットは自動的に新しい Primary ノードを選出する。
  • Secondary ノード
    • Primary ノードからデータを複製し、データの冗長性を確保する。
    • Primary ノードがダウンした場合、新しい Primary ノードの候補になる。
    • 設定によっては、クライアントからの読み込み要求を処理することも可能。これにより、読み込み負荷を分散させることができる。
    • 常に Primary ノードからの oplog を適用し、データの整合性を保つ。
  • Arbiter ノード(必須ではない)
    • データを持たない特殊なノードで、Primary ノードの選出にのみ参加する。
    • データを持たないため、ディスクの容量を節約する。
    • 主に、レプリカセットのノード数を奇数にするために使用される。これにより、Primary ノードの選出がより安定する。
    • Arbiter は投票にのみ参加し、データの複製やクライアントからの読み込み要求を処理しない。

レプリカセットの動作

  1. データの複製
    • Primary ノードで行われた書き込み操作は、oplog と呼ばれるログに記録される。
    • Secondary ノードは、oplog を Secondary ノードから取得し、自身のデータに適用することで、Primary ノードと同一のデータを保持する。
  2. Primary ノードの選出
    • Primary ノードがダウンした場合、レプリカセット内のノード間で選挙が行われ、新しいノードが選出される。
    • 選挙には、各ノードの優先度やデータの状態などが考慮される。

レプリカセットを構築してみる

Docker や MongoDB の知識が未熟なので、必要最低限レプリカセットを構築できる設定となっています。

まずは MongoDB のコンテナを3つ用意するので、プロジェクトのルートに compose.yml を作成する。

./compose.yml
services:
  mongodb-primary:
    image: mongo:7
    container_name: mongodb-primary
    hostname: mongodb-primary
    # rs0 の部分は rs.initiate の _id と同じ値にする
    command: ["mongod", "--replSet", "rs0", "--bind_ip_all"]
    ports:
      - "27017:27017"
    networks:
      - hoge-network
    volumes:
      # データの永続化
      - mongodb-primary-data:/data/db
      # レプリカセットの初期化処理を行うスクリプトをマウント
      - ./docker/mongodb/init.js:/init.js
    restart: always
    depends_on:
      - mongodb-secondary
      - mongodb-arbiter
  mongodb-secondary:
    image: mongo:7
    container_name: mongodb-secondary
    hostname: mongodb-secondary
    command: ["mongod", "--replSet", "rs0", "--bind_ip_all"]
    networks:
      - hoge-network
    volumes:
      # データの永続化
      - mongodb-secondary-data:/data/db
    restart: always
  mongodb-arbiter:
    image: mongo:7
    container_name: mongodb-arbiter
    hostname: mongodb-arbiter
    command: ["mongod", "--replSet", "rs0", "--bind_ip_all"]
    networks:
      - hoge-network
    restart: always

networks:
  hoge-network:

volumes:
  mongodb-primary-data:
  mongodb-secondary-data:

レプリカセットの初期化処理を行うために、init.js ファイルを作成して rs.initiate を書く。

./docker/mongodb/init.js
rs.initiate({
  _id: "rs0",
  members: [
    // コンテナの hostname と port を指定
    // priority は優先順位を決める値(任意)
    { _id: 0, host: "mongodb-primary:27017", priority: 100 },
    { _id: 1, host: "mongodb-secondary:27017", priority: 10 },
    // arbiterOnly: true で Arbiter ノードになる
    { _id: 2, host: "mongodb-arbiter:27017", arbiterOnly: true },
  ],
});

コンテナを起動する。

docker compose up -d

mongodb-primary コンテナでレプリカセットの初期化を行う。

docker exec -i mongodb-primary mongosh /init.js

レプリカセットになっているか mongodb-primary コンテナの中で mongosh に接続して確認してみる。

docker compose exec mongodb-primary mongosh

rs0 [direct: primary] test> と表示されていればレプリカセットの構築ができている。

Discussion