MongoDB で 3台構成 の レプリカセット を 構築する 方法

0 件のコメント

今回は「MongoDB で 3台構成 の レプリカセット を 作成する方法」についてまとめます。

概要

今回は以下の図のようなサーバー3台構成(プライマリ1台、セカンダリ2台)のMongoDBサーバーを構築していきます。

今回は動作確認をお試しで行いたいので、以下の制約をつけた環境でのサンプルになります。

  • 1台の物理マシンの中に上記3インスタンスを構築
  • 認証制御は行わない

どちらかというと本番向けというよりは開発環境向けのデータベースサーバー構築になります。

レプリカセットの構築

今回はテスト用として物理1台の中に3台分のMongoDBインスタンスを作成するサンプルです。 実運用だと1サーバー1インスタンスになるはずなので、一部設定は読み替えていただければと思います。

レプリカセットメンバーの準備

  1. 各インスタンス用にフォルダ・ファイルを作成

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    C:\mongodb
      
      ├ \server1
      │  ├ \data
      │  ├ \log
      │  └ mongod.srver1.cfg
      │    
      ├ \server2
      │  ├ \data
      │  ├ \log
      │  └ mongod.server2.cfg
      │    
      └ \server3
          ├ \data
          ├ \log
          └ mongod.server3.cfg
  2. 各インスタンスの設定ファイル(mongod.serverN.cfg)を修正

    1サーバー中に複数インスタンス生成しているため、ポート番号を分けています。 1サーバー1インスタンスであればポートはすべて同じ (27017 など) でも問題ないです。

    レプリカセット名(replSetName)はすべて共通(今回は rs0 )で設定しておきます。 また、開発環境向けであれば bindIpAll 設定を入れておくとバインドIPを列挙しなくてよいので設定が簡単です。 プロダクション向けは bindIp を面倒でも設定しておくほうが良いと思いますが…。

    mongod.srver1.cfg

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    systemLog:
      destination: file
      path: C:\mongodb\server1\log\mongod.srver1.log
    storage:
      dbPath: C:\mongodb\server1\data
    replication:
      replSetName: "rs0"
    net:
      bindIpAll: true
      port: 27001

    mongod.server2.cfg

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    systemLog:
      destination: file
      path: C:\mongodb\server2\log\mongod.server2.log
    storage:
      dbPath: C:\mongodb\server2\data
    replication:
      replSetName: "rs0"
    net:
      bindIpAll: true
      port: 27002

    mongod.server3.cfg

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    systemLog:
      destination: file
      path: C:\mongodb\server3\log\mongod.server3.log
    storage:
      dbPath: C:\mongodb\server3\data
    replication:
      replSetName: "rs0"
    net:
      bindIpAll: true
      port: 27003
  3. 各インスタンスを起動

    分かりやすいようコマンドプロンプトを3つ立ち上げてそれぞれのインスタンスを起動します。

    1
    mongod --config "C:\mongodb\server1\mongod.srver1.cfg"
    1
    mongod --config "C:\mongodb\server2\mongod.server2.cfg"
    1
    mongod --config "C:\mongodb\server3\mongod.server3.cfg"

レプリカセットの初期化

  1. いずれかのインスタンスにログイン

    今回は以下のコマンドを実行して server1 へログインします。

    1
    mongo --host 127.0.0.1:27001
  2. レプリカセット初期化処理の実行

    mongoコマンドの rs.initiate() を実行することでレプリカセットを初期化します。 渡したい引数はあらかじめ config オブジェクトへ代入してから渡します(そのほうが誤りを訂正できるので)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    > config = {
       _id : "rs0",
       members: [
          { _id: 0, host: "127.0.0.1:27001" },
          { _id: 1, host: "127.0.0.1:27002" },
          { _id: 2, host: "127.0.0.1:27003" },
       ]
    }
    > rs.initiate(config)

以上で設定は完了してレプリカセットが利用できる状態になりました。 次の章で簡単な動作確認をしてみます。

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

今回は動作確認として以下の以下の3つを行ってみます。

  • レプリカセットの設定確認
  • レプリカセットのステータス確認
  • フェールオーバーの動作確認

レプリカセットの設定確認

  1. コマンドプロンプトで rs.config() を実行

    1
    > rs.config()
  2. コマンド実行結果としてレプリカセット設定が表示されることを確認

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    {
      "_id" : "rs0",
      "version" : 1,
      "protocolVersion" : NumberLong(1),
      "members" : [
        {
          "_id" : 0,
          "host" : "127.0.0.1:8001",
          "arbiterOnly" : false,
          "buildIndexes" : true,
          "hidden" : false,
          "priority" : 1,
          "tags" : {
     
          },
          "slaveDelay" : NumberLong(0),
          "votes" : 1
        },
        {
          "_id" : 1,
          "host" : "127.0.0.1:8002",
          "arbiterOnly" : false,
          "buildIndexes" : true,
          "hidden" : false,
          "priority" : 1,
          "tags" : {
     
          },
          "slaveDelay" : NumberLong(0),
          "votes" : 1
        },
        {
          "_id" : 2,
          "host" : "127.0.0.1:8003",
          "arbiterOnly" : false,
          "buildIndexes" : true,
          "hidden" : false,
          "priority" : 1,
          "tags" : {
     
          },
          "slaveDelay" : NumberLong(0),
          "votes" : 1
        }
      ],
      "settings" : {
        "chainingAllowed" : true,
        "heartbeatIntervalMillis" : 2000,
        "heartbeatTimeoutSecs" : 10,
        "electionTimeoutMillis" : 10000,
        "catchUpTimeoutMillis" : -1,
        "catchUpTakeoverDelayMillis" : 30000,
        "getLastErrorModes" : {
     
        },
        "getLastErrorDefaults" : {
          "w" : 1,
          "wtimeout" : 0
        },
        "replicaSetId" : ObjectId("5a75b603abca086c328afd4f")
      }
    }

サーバーのステータス確認

  1. コマンドで rs.status() を実行

    1
    > rs.status()
  2. コマンド実行結果として現在のサーバーステータスが表示されることを確認

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    {
      "set" : "rs0",
      "date" : ISODate("2018-02-03T13:21:42.450Z"),
      "myState" : 1,
      "term" : NumberLong(1),
      "heartbeatIntervalMillis" : NumberLong(2000),
      "optimes" : {
        "lastCommittedOpTime" : {
          "ts" : Timestamp(1517664101, 1),
          "t" : NumberLong(1)
        },
        "readConcernMajorityOpTime" : {
          "ts" : Timestamp(1517664101, 1),
          "t" : NumberLong(1)
        },
        "appliedOpTime" : {
          "ts" : Timestamp(1517664101, 1),
          "t" : NumberLong(1)
        },
        "durableOpTime" : {
          "ts" : Timestamp(1517664101, 1),
          "t" : NumberLong(1)
        }
      },
      "members" : [
        {
          "_id" : 0,
          "name" : "127.0.0.1:8001",
          "health" : 1,
          "state" : 1,
          "stateStr" : "PRIMARY",
          "uptime" : 602,
          "optime" : {
            "ts" : Timestamp(1517664101, 1),
            "t" : NumberLong(1)
          },
          "optimeDate" : ISODate("2018-02-03T13:21:41Z"),
          "electionTime" : Timestamp(1517663759, 1),
          "electionDate" : ISODate("2018-02-03T13:15:59Z"),
          "configVersion" : 1,
          "self" : true
        },
        {
          "_id" : 1,
          "name" : "127.0.0.1:8002",
          "health" : 1,
          "state" : 2,
          "stateStr" : "SECONDARY",
          "uptime" : 354,
          "optime" : {
            "ts" : Timestamp(1517664101, 1),
            "t" : NumberLong(1)
          },
          "optimeDurable" : {
            "ts" : Timestamp(1517664101, 1),
            "t" : NumberLong(1)
          },
          "optimeDate" : ISODate("2018-02-03T13:21:41Z"),
          "optimeDurableDate" : ISODate("2018-02-03T13:21:41Z"),
          "lastHeartbeat" : ISODate("2018-02-03T13:21:41.665Z"),
          "lastHeartbeatRecv" : ISODate("2018-02-03T13:21:40.647Z"),
          "pingMs" : NumberLong(0),
          "syncingTo" : "127.0.0.1:8001",
          "configVersion" : 1
        },
        {
          "_id" : 2,
          "name" : "127.0.0.1:8003",
          "health" : 1,
          "state" : 2,
          "stateStr" : "SECONDARY",
          "uptime" : 354,
          "optime" : {
            "ts" : Timestamp(1517664101, 1),
            "t" : NumberLong(1)
          },
          "optimeDurable" : {
            "ts" : Timestamp(1517664101, 1),
            "t" : NumberLong(1)
          },
          "optimeDate" : ISODate("2018-02-03T13:21:41Z"),
          "optimeDurableDate" : ISODate("2018-02-03T13:21:41Z"),
          "lastHeartbeat" : ISODate("2018-02-03T13:21:41.662Z"),
          "lastHeartbeatRecv" : ISODate("2018-02-03T13:21:40.652Z"),
          "pingMs" : NumberLong(0),
          "syncingTo" : "127.0.0.1:8001",
          "configVersion" : 1
        }
      ],
      "ok" : 1,
      "operationTime" : Timestamp(1517664101, 1),
      "$clusterTime" : {
        "clusterTime" : Timestamp(1517664101, 1),
        "signature" : {
          "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
          "keyId" : NumberLong(0)
        }
      }
    }

フェールオーバーの動作確認

MongoDBではプライマリサーバーがダウンしたとき(通信不能になったとき)、自動でセカンダリサーバーがプライマリサーバーに昇格するようになっています。 今回はプライマリサーバーを強制的に落としてセカンダリサーバーのどちらかがプライマリサーバーに昇格することを確認します。

  1. 現在のステータスを確認

    先述の rs.status() で状況を確認します。 結果出力内容は一部省略しています。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    > rs.status()
    {
      ...
      "members" : [
        {
          "_id" : 0,
          "name" : "127.0.0.1:8001",
          "health" : 1,
          "state" : 1,
          "stateStr" : "PRIMARY",
          ...
        },
        {
          "_id" : 1,
          "name" : "127.0.0.1:8002",
          "health" : 1,
          "state" : 2,
          "stateStr" : "SECONDARY",
          ...
        },
        {
          "_id" : 2,
          "name" : "127.0.0.1:8003",
          "health" : 1,
          "state" : 2,
          "stateStr" : "SECONDARY",
          ...
        }
      ],
      ...
    }
  2. プライマリサーバーのコマンドプロンプトを停止

    先ほどの rs.status() の結果から _id: 0 のサーバーがプライマリサーバーだとわかりましたので、 _id: 0 のサーバーを起動しているコマンドプロンプト上で Ctrl + C を実行し、停止させます。

  3. ステータスの確認

    ハートビート(生死確認)は2秒間隔なので、3秒程度待ってから rs.status() を実行します。 セカンダリサーバーのどちらかがプライマリサーバーに昇格していることが確認できます。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    > rs.status()
    {
      ...
      "members" : [
        {
          "_id" : 0,
          "name" : "127.0.0.1:8001",
          "health" : 0,
          "state" : 8,
          "stateStr" : "(not reachable/healthy)",
          ...
        },
        {
          "_id" : 1,
          "name" : "127.0.0.1:8002",
          "health" : 1,
          "state" : 1,
          "stateStr" : "PRIMARY",
          ...
        },
        {
          "_id" : 2,
          "name" : "127.0.0.1:8003",
          "health" : 1,
          "state" : 2,
          "stateStr" : "SECONDARY",
          ...
        }
      ],
      ...
    }

今回は「MongoDBの3台構成レプリカセットの構築」についてまとめました。 ポイントは以下の通りです。

  • 3台構成の場合、プライマリ1台+セカンダリ2台
  • 1台サーバーに3インスタンスの場合、ポートを分ける

参考になったでしょうか? 本記事がお役に立っていると嬉しいです!!

参考記事

最後に… このブログに興味を持っていただけた方は、 ぜひ 「Facebookページ に いいね!」または 「Twitter の フォロー」 お願いします!!