Carpe Diem

備忘録。https://github.com/jun06t

MongoDBでシャーディング

概要

MongoDBでシャーディングを構築します。
MongoDBのインストールですでにインストールしている前提で進めます。

環境

今回は1台でポートを別にして複数プロセスで構築します。
configサーバは1 or 3台必要(2だとサポート外で怒られます)なので、単一障害点とならないよう今回は3つにします。

名前 役割 今回使用するport
mongos ルーティング 20000
config0 シャーディングのメタデータを管理 30000
config1 同上 30001
config2 同上 30002
node0 シャード 40000
node1 同上 40001
node2 同上 40002

各プロセスの起動

デフォルトのプロセスを停止

$ sudo service mongod stop

ディレクトリ用意

複数プロセスで起動するのでデータの保存先を変えるためディレクトリを作成します。

# cd /var/lib/mongodb
# mkdir config0
# mkdir config1
# mkdir config2
# mkdir node0
# mkdir node1
# mkdir node2

configサーバ起動

--configsvrオプションをつけるとconfigサーバとして起動します。forkをつけてバックグラウンドで動くようにします。

# mongod --configsvr --port 30000 --dbpath /var/lib/mongodb/config0 --logpath /var/log/mongodb/config0.log --fork
# mongod --configsvr --port 30001 --dbpath /var/lib/mongodb/config1 --logpath /var/log/mongodb/config1.log --fork
# mongod --configsvr --port 30002 --dbpath /var/lib/mongodb/config2 --logpath /var/log/mongodb/config2.log --fork

mongosサーバ起動

さきほどのconfigサーバをlocalhost:30000,localhost:30001,localhost:30002といったカンマ区切りで指定します。

# mongos --configdb localhost:30000,localhost:30001,localhost:30002 --port 20000 --logpath /var/log/mongodb/mongos.log --chunkSize 1 --fork

チャンクサイズはデフォルトでは64Mですが、今回はチャンクが分割される動作を確認したいために小さい1MBに設定します。

mongodサーバ起動

--shardsvrオプションをつけます。

# mongod --shardsvr --port 40000 --dbpath /var/lib/mongodb/node0 --logpath /var/log/mongodb/node0.log --fork
# mongod --shardsvr --port 40001 --dbpath /var/lib/mongodb/node1 --logpath /var/log/mongodb/node1.log --fork
# mongod --shardsvr --port 40002 --dbpath /var/lib/mongodb/node2 --logpath /var/log/mongodb/node2.log --fork

動作確認

以下のようにプロセスがあればOKです。

# ps x | grep mongo
16969 ?        Sl     0:02 mongod --configsvr --port 30000 --dbpath /var/lib/mongodb/config0 --logpath /var/log/mongodb/config0.log --fork
16995 ?        Sl     0:02 mongod --configsvr --port 30001 --dbpath /var/lib/mongodb/config1 --logpath /var/log/mongodb/config1.log --fork
17015 ?        Sl     0:00 mongod --configsvr --port 30002 --dbpath /var/lib/mongodb/config2 --logpath /var/log/mongodb/config2.log --fork
17029 ?        Sl     0:00 mongos --configdb localhost:30000,localhost:30001,localhost:30002 --port 20000 --logpath /var/log/mongodb/mongos.log --chunkSize 1 --fork
17091 ?        Sl     0:00 mongod --shardsvr --port 40000 --dbpath /var/lib/mongodb/node0 --logpath /var/log/mongodb/node0.log --fork
17104 ?        Sl     0:00 mongod --shardsvr --port 40001 --dbpath /var/lib/mongodb/node1 --logpath /var/log/mongodb/node1.log --fork
17117 ?        Sl     0:00 mongod --shardsvr --port 40002 --dbpath /var/lib/mongodb/node2 --logpath /var/log/mongodb/node2.log --fork

シャーディング

シャードの追加

mongosサーバにシャードを追加していきます。

$ mongo localhost:20000

mongosサーバに入り、

mongos> sh.addShard("localhost:40000")
{ "shardAdded" : "shard0000", "ok" : 1 }

mongos> sh.addShard("localhost:40001")
{ "shardAdded" : "shard0000", "ok" : 1 }

mongos> sh.addShard("localhost:40002")
{ "shardAdded" : "shard0000", "ok" : 1 }

各シャードを追加します。
今回はすべて同じサーバなので問題無いですが、複数台使う際はlocalhost別のFQDNを混ぜて使わないでください。エラーが起きます。

確認してみます。

mongos> sh.status()
--- Sharding Status --- 
  sharding version: {
    "_id" : 1,
    "version" : 4,
    "minCompatibleVersion" : 4,
    "currentVersion" : 5,
    "clusterId" : ObjectId("54e73fa06ae061cf73d0d5a8")
}
  shards:
    {  "_id" : "shard0000",  "host" : "localhost:40000" }
    {  "_id" : "shard0001",  "host" : "localhost:40001" }
    {  "_id" : "shard0002",  "host" : "localhost:40002" }

大丈夫そうですね。

シャーディングの有効化

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

mongos> sh.enableSharding("logdb")
{ "ok" : 1 }

シャードキーの設定

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

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

シャードキーの注意点

今回は_idをキーにしていますが、実際に運用する際は以下のことに注意してください。

  • 適切にバランシングできるよう、シャードキーはランダムな値が望ましい。
  • 一度シャードキーを設定したら変更はできない。
  • すでにデータが入っているコレクションに対してシャーディングを設定する場合、シャードキーはインデックスをつけている必要がある。
  • シャードキーに設定したフィールドは値をupdateできない。する場合一度removeしてinsertする必要がある。

動作確認

ダミーデータを入れてみます。_idは自動でつくので、適当なデータを入れます。

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

ステータスを確認してみます。

mongos> sh.status()
--- Sharding Status --- 
  shards:
    {  "_id" : "shard0000",  "host" : "localhost:40000" }
    {  "_id" : "shard0001",  "host" : "localhost:40001" }
    {  "_id" : "shard0002",  "host" : "localhost:40002" }
  databases:
    {  "_id" : "admin",  "partitioned" : false,  "primary" : "config" }
    {  "_id" : "test",  "partitioned" : false,  "primary" : "shard0000" }
    {  "_id" : "logdb",  "partitioned" : true,  "primary" : "shard0000" }
        logdb.users
            shard key: { "_id" : 1 }
            chunks:
                shard0002   4
                shard0000   4
                shard0001   4

チャンクがちゃんと等分されていますね。シャーディングができている証拠です。

一応直接各ノードのDBにアクセスして確認してみましょう。

node0

$ mongo localhost:40000
> use logdb
> db.users.count()
35751

node1

$ mongo localhost:40001
> use logdb
> db.users.count()
42987

node2

$ mongo localhost:40002
> use logdb
> db.users.count()
21262

合計すると挿入した10万ドキュメントになります。
以上です。お疲れ様でした。

ソース