Carpe Diem

備忘録

MongoDB 4.2でシャーディング・レプリカセットのクラスタ構築

概要

気づいたらMongoDBも4.2になっていました。
以前に

DockerでMongoDBのレプリカセットを構築 - Carpe Diem

レプリケーションを、

MongoDBでシャーディング - Carpe Diem

でシャーディングを構築しましたが、設定項目が代わっていたりしたので復習がてらdocker上で構築検証しました。

大まかな流れは変わらないため、↑の記事を読んでおくとスムーズに進められます。

環境

  • MongoDB 4.2
  • Docker 19.03.2

クラスタ構成

種類 レプリカ名 台数
config configRepl 3
mongod shard shardRepl_1 3
mongod shard shardRepl_2 3
mongod shard shardRepl_3 3
mongos - 1

の計13台です。

以下のような形です。

検証コード

この検証で使っているコードは以下です。

github.com

設定

各設定を順に説明していきます。

docker-compose.yml

まずdocker-composeです。

Config server

基本的に起動時にconfigを指定する形式にしておきます。

  mongoc001: &mongoc
    container_name: mongoc001
    image: mongo:4.2
    networks:
      - mongo_net
    volumes:
      - ./mongoc.conf:/etc/mongoc.conf
    command: mongod --config /etc/mongoc.conf
  mongoc002:
    <<: *mongoc
    container_name: mongoc002
  mongoc003:
    <<: *mongoc
    container_name: mongoc003

mongoc.conf

設定ファイルは以下です。

sharding:
  clusterRole: configsvr
replication:
  replSetName: configRepl
net:
  port: 27019
  bindIp: 0.0.0.0
storage:
  dbPath: /data/configdb
  journal:
    enabled: true

ポイントはbindIp0.0.0.0にしているところです。MongoDB 3.6からデフォルトだとlocalhostになっており、疎通ができなくなります。
※dockerでは開発しやすいよう引数与えないと自動で0.0.0.0なります。

bindipって何?という方は以下を参考にしてください。

bindアドレスとadvertiseアドレス - Carpe Diem

また3.4からconfigサーバでレプリカセットを組むことが必須になっているので、replicationの設定もしています。

configsvrのデフォルトポートは27019なのでそれを指定します。

Mongod shard server

こちらも先程のように各シャード毎にレプリカセットを組めるように用意します。

  mongod001: &shardRepl_1
    container_name: shardRepl_1_001
    image: mongo:4.2
    networks:
      - mongo_net
    volumes:
      - ./mongod_1.conf:/etc/mongod.conf
    command: mongod --config /etc/mongod.conf
  mongod002:
    <<: *shardRepl_1
    container_name: shardRepl_1_002
  mongod003:
    <<: *shardRepl_1
    container_name: shardRepl_1_003

  mongod004: &shardRepl_2
    <<: *shardRepl_1
    container_name: shardRepl_2_001
    volumes:
      - ./mongod_2.conf:/etc/mongod.conf
  mongod005:
    <<: *shardRepl_2
    container_name: shardRepl_2_002
  mongod006:
    <<: *shardRepl_2
    container_name: shardRepl_2_003

  mongod007: &shardRepl_3
    <<: *shardRepl_1
    container_name: shardRepl_3_001
    volumes:
      - ./mongod_3.conf:/etc/mongod.conf
  mongod008:
    <<: *shardRepl_3
    container_name: shardRepl_3_002
  mongod009:
    <<: *shardRepl_3
    container_name: shardRepl_3_003

mongod_n.conf

先程と似ていますが、clusterRole: shardsvrとなっています。
またシャード毎にレプリカセットを用意するため別ファイルにしています。
これは1つめのシャードの設定なのでreplSetName: shardRepl_1となっています。

sharding:
  clusterRole: shardsvr
replication:
  replSetName: shardRepl_1
net:
  port: 27018
  bindIp: 0.0.0.0
storage:
  dbPath: /data/db
  journal:
    enabled: true

shardsvrのデフォルトポートは27018なのでそれを使います。

Mongos

mongosの起動時はmongodでなくmongosです。
またmongosのみport forward設定しています。

  mongos001:
    container_name: mongos001
    image: mongo:4.2
    networks:
      - mongo_net
    volumes:
      - ./mongos.conf:/etc/mongos.conf
    command: mongos --config /etc/mongos.conf
    ports:
      - "27017:27017"

mongs.conf

sharding:
  configDB: configRepl/mongoc001:27019,mongoc002:27019,mongoc003:27019
net:
  port: 27017
  bindIp: 0.0.0.0

ポイントはsharding.configDBでconfigサーバのレプリカセットを指定している点です。

起動後の設定

上記をdocker-composeで起動した後の設定をしていきます。

Config server

コンテナに入って

$ docker exec -it mongoc001 mongo --port 27019

レプリケーション設定を行います。

> config = {
  "_id": "configRepl",
  "members": [
    {"_id": 0, "host": "mongoc001:27019"},
    {"_id": 1, "host": "mongoc002:27019"},
    {"_id": 2, "host": "mongoc003:27019"}
  ]
}

> rs.initiate(config)

Mongod shard server

同様にレプリカセットを構築しますが、PSAアーキテクチャ

f:id:quoll00:20190920185435p:plain

ではなく、Secondaryが2つの形にします。

f:id:quoll00:20190920185455p:plain

理由は3.6から細かく設定できるようになったRead concernのデフォルトがmajorityなのですが、PSA構成だとダウン時にstorage cacheが増加しパフォーマンスに影響が出るためOFFにした方が良いようです。 しかしRead concernの推奨としてはmajorityなので、Secondary2台構成にします。

IMPORTANT

In general, avoid disabling "majority" read concern unless necessary. However, if you have a three-member replica set with a primary-secondary-arbiter (PSA) architecture or a sharded cluster with a three-member PSA shard, disable to prevent the storage cache pressure from immobilizing the deployment.

ref: https://docs.mongodb.com/manual/reference/read-concern-majority/#disable-read-concern-majority

shardRepl_1

同様にコンテナに入って

$ docker exec -it shardRepl_1_001 mongo --port 27018

レプリケーション設定を行います。

> config = {
  "_id": "shardRepl_1",
  "members": [
    {"_id": 0, "host": "shardRepl_1_001:27018"},
    {"_id": 1, "host": "shardRepl_1_002:27018"},
    {"_id": 2, "host": "shardRepl_1_003:27018"}
  ]
}

> rs.initiate(config)

他のレプリカセットも同様に設定します。

shardRepl_2

$ docker exec -it shardRepl_2_001 mongo --port 27018
> config = {
  "_id": "shardRepl_2",
  "members": [
    {"_id": 0, "host": "shardRepl_2_001:27018"},
    {"_id": 1, "host": "shardRepl_2_002:27018"},
    {"_id": 2, "host": "shardRepl_2_003:27018"}
  ]
}

> rs.initiate(config)

shardRepl_3

$ docker exec -it shardRepl_3_001 mongo --port 27018
> config = {
  "_id": "shardRepl_3",
  "members": [
    {"_id": 0, "host": "shardRepl_3_001:27018"},
    {"_id": 1, "host": "shardRepl_3_002:27018"},
    {"_id": 2, "host": "shardRepl_3_003:27018"}
  ]
}

> rs.initiate(config)

Mongos server

mongosはポートフォワーディングしているのでそのままアクセスできます。

$ mongo localhost:27017

シャードの登録

mongodをshardとして登録します。
レプリカセットの全サーバを入れる必要はなく、1つだけ指定しておけば大丈夫です。

mongos> sh.addShard("shardRepl_1/shardRepl_1_001:27018")
mongos> sh.addShard("shardRepl_2/shardRepl_2_001:27018")
mongos> sh.addShard("shardRepl_3/shardRepl_3_001:27018")

確認します。

mongos> sh.status()
--- Sharding Status ---
  sharding version: {
        "_id" : 1,
        "minCompatibleVersion" : 5,
        "currentVersion" : 6,
        "clusterId" : ObjectId("5d84899c781951790530e119")
  }
  shards:
        {  "_id" : "shardRepl_1",  "host" : "shardRepl_1/shardRepl_1_001:27018,shardRepl_1_002:27018,shardRepl_1_003:27018",  "state" : 1 }
        {  "_id" : "shardRepl_2",  "host" : "shardRepl_2/shardRepl_2_001:27018,shardRepl_2_002:27018,shardRepl_2_003:27018",  "state" : 1 }
        {  "_id" : "shardRepl_3",  "host" : "shardRepl_3/shardRepl_3_001:27018,shardRepl_3_002:27018,shardRepl_3_003:27018",  "state" : 1 }

登録されてます。

有効化

logdbというDBに対してシャーディングを有効化します。

mongos> sh.enableSharding("logdb")

シャードindexの追加

次にコレクションに対してシャードキーの設定をします。
usersというコレクションの_idフィールドに設定することにします。

mongos> sh.shardCollection("logdb.users", {"_id": 1})

動作確認

検証時にシャーディングのバランシングがされやすいよう、chunkSizeを変更しておきます。
3.4からsharding.chunkSizeはconfigファイルの設定項目から消えているので注意してください。

mongos> use config
switched to db config

mongos> db.settings.save({ _id:"chunksize", value: 1})
WriteResult({ "nMatched" : 0, "nUpserted" : 1, "nModified" : 0, "_id" : "chunksize" })

データ投入

ループでダミーデータを入れます。

mongos> use logdb

mongos> for (var i = 1; i <= 100000; i++) {
   db.users.insert({number: i , name: "foo"+i})
}

バランシング確認

ちゃんとバランシングされていることが分かります。

mongos> sh.status()
--- Sharding Status ---
...
  autosplit:
        Currently enabled: yes
  balancer:
        Currently enabled:  yes
        Currently running:  no
        Failed balancer rounds in last 5 attempts:  0
        Migration Results for the last 24 hours:
                5 : Success
  databases:
...
        {  "_id" : "logdb",  "primary" : "shardRepl_2",  "partitioned" : true,  "version" : {  "uuid" : UUID("ea5a63e9-b9cd-4629-8201-0f596a5c5924"),  "lastMod" : 1 } }
                logdb.users
                        shard key: { "_id" : 1 }
                        unique: false
                        balancing: true
                        chunks:
                                shardRepl_1     3
                                shardRepl_2     3
                                shardRepl_3     3
                        { "_id" : { "$minKey" : 1 } } -->> { "_id" : ObjectId("5d848f3c1cd4a5e8cfb6f796") } on : shardRepl_3 Timestamp(6, 1)
                        { "_id" : ObjectId("5d848f3c1cd4a5e8cfb6f796") } -->> { "_id" : ObjectId("5d848f611cd4a5e8cfb740ba") } on : shardRepl_1 Timestamp(5, 1)
                        { "_id" : ObjectId("5d848f611cd4a5e8cfb740ba") } -->> { "_id" : ObjectId("5d848f751cd4a5e8cfb7654c") } on : shardRepl_2 Timestamp(4, 1)
                        { "_id" : ObjectId("5d848f751cd4a5e8cfb7654c") } -->> { "_id" : ObjectId("5d848f911cd4a5e8cfb79688") } on : shardRepl_2 Timestamp(3, 3)
                        { "_id" : ObjectId("5d848f911cd4a5e8cfb79688") } -->> { "_id" : ObjectId("5d848faa1cd4a5e8cfb7bb1a") } on : shardRepl_1 Timestamp(4, 2)
                        { "_id" : ObjectId("5d848faa1cd4a5e8cfb7bb1a") } -->> { "_id" : ObjectId("5d848fcb1cd4a5e8cfb7ecd2") } on : shardRepl_1 Timestamp(4, 3)
                        { "_id" : ObjectId("5d848fcb1cd4a5e8cfb7ecd2") } -->> { "_id" : ObjectId("5d848fdf1cd4a5e8cfb81164") } on : shardRepl_3 Timestamp(5, 2)
                        { "_id" : ObjectId("5d848fdf1cd4a5e8cfb81164") } -->> { "_id" : ObjectId("5d848ffb1cd4a5e8cfb84325") } on : shardRepl_3 Timestamp(5, 3)
                        { "_id" : ObjectId("5d848ffb1cd4a5e8cfb84325") } -->> { "_id" : { "$maxKey" : 1 } } on : shardRepl_2 Timestamp(6, 0)

ソース