MongoDB で複数シャードを立ち上げる。

最近MongoDBに取り組んでいます。これは、1台のwindowsマシンで2つのシャードを立ち上げたときのメモです。大量emailデータをMongoDBで管理することを想定しています。
MongoDBのインストール方法は

データディレクトリ作成

コマンドプロンプトから実行します。やり直すときは、ここのディレクトリファイルを削除してしまえばよいです。

mkdir \mongo\data\shard_test1\shard0
mkdir \mongo\data\shard_test1\shard1
mkdir \mongo\data\shard_test1\config

サービス達を起動

これもコマンドプロンプトから実行します。

start \mongo\bin\mongod --shardsvr  --dbpath \mongo\data\shard_test1\shard0 --port 27101
start \mongo\bin\mongod --shardsvr  --dbpath \mongo\data\shard_test1\shard1 --port 27102
start \mongo\bin\mongod --configsvr --dbpath \mongo\data\shard_test1\config --port 27103
start \mongo\bin\mongos --configdb localhost:27103 --port 27104

mongod はサーバープログラム、mongos はルータープログラムです。
ここまでではmongos(port:27104) は mongod:configsvr(port:27103) を参照しているが、mongod:shardsvr(port:27101), mongod:shardsvr(port:27102)は参照されていません。

mongo コンソール起動

コマンドプロンプトから mongo コンソールを起動します。mongos(port:27104)へ接続します。

\mongo\bin\mongo localhost:27104/admin

シャードの初期状態を確認

mongo コンソールからシャードの状態を確認します。当然ながらなんにもありません。

Shardingの管理

> db.runCommand( { listshards : 1 } )
{ "shards" : [ ], "ok" : 1 }
> db.printShardingStatus()
--- Sharding Status ---
  sharding version: { "_id" : 1, "version" : 3 }
  shards:
  databases:
        { "_id" : "admin", "partitioned" : false, "primary" : "config" }

>

シャードを登録

mongo コンソールからシャードを追加します。ここでmongod:shardsvr(port:27101), mongod:shardsvr(port:27102) が現れます。

Shardingの設定

> db.runCommand( { addshard : "localhost:27101" } )
{ "shardAdded" : "shard0000", "ok" : 1 }
> db.runCommand( { addshard : "localhost:27102" } )
{ "shardAdded" : "shard0001", "ok" : 1 }

? maxSize パラメータを試してみたけど、想定どおりに利かなかった。あとでまた試そう。
? allowLocal:true をあとで調べよう。

シャードを確認

mongo コンソールからシャードの状態を確認します。

> db.runCommand( { listshards : 1 } )
{
        "shards" : [
                {
                        "_id" : "shard0000",
                        "host" : "localhost:27101"
                },
                {
                        "_id" : "shard0001",
                        "host" : "localhost:27102"
                }
        ],
        "ok" : 1
}
> db.printShardingStatus()
--- Sharding Status ---
  sharding version: { "_id" : 1, "version" : 3 }
  shards:
      { "_id" : "shard0000", "host" : "localhost:27101" }
      { "_id" : "shard0001", "host" : "localhost:27102" }
  databases:
        { "_id" : "admin", "partitioned" : false, "primary" : "config" }

>

これでシャードが登録されました。

test データベース、emails コレクションをシャード対象にする

シャードを登録したあと、データベース、コレクションをシャード対象します。 Shardingの設定をおさらいしましょう。mongoコンソールから実行。

> db.runCommand( { enablesharding : "test" } );
{ "ok" : 1 }
> db.runCommand( { shardcollection : "test.emails", key : {id:1} });
{ "collectionsharded" : "test.emails", "ok" : 1 }
>

んで確認。

> db.printShardingStatus()
--- Sharding Status ---
  sharding version: { "_id" : 1, "version" : 3 }
  shards:
      { "_id" : "shard0000", "host" : "localhost:27101" }
      { "_id" : "shard0001", "host" : "localhost:27102" }
  databases:
        { "_id" : "admin", "partitioned" : false, "primary" : "config" }
        { "_id" : "test", "partitioned" : true, "primary" : "shard0000" }
                test.emails chunks:
                        { "id" : { $minKey : 1 } } -->> { "id" : { $maxKey : 1 }
 } on : shard0000 { "t" : 1000, "i" : 0 }

>

test.emails がシャーディング対象になっています

データ投入

こんな感じのjavascriptで手軽に大量データを作れるのが素敵。「use test」を忘れずに。mongoコンソールからでもいいですが、rockmongoもいいですよね。

function () {
for(i=0;i<100000;i++){db.emails.save({id:i, from:(i%100)+1, to:[(i%100)+2, (i%100)+3, (i%100)+4, (i%100)+5], subject:"subject"+i, body:"body"+i });};
}

投入後のデータ確認

> db.emails.findOne()
{
        "_id" : ObjectId("4d651201ba6e000000019c9b"),
        "id" : 0,
        "from" : 1,
        "to" : [
                2,
                3,
                4,
                5
        ],
        "subject" : "subject0",
        "body" : "body0"
}
> db.emails.count()
100000
> db.printShardingStatus()
--- Sharding Status ---
  sharding version: { "_id" : 1, "version" : 3 }
  shards:
      { "_id" : "shard0000", "host" : "localhost:27101" }
      { "_id" : "shard0001", "host" : "localhost:27102" }
  databases:
        { "_id" : "admin", "partitioned" : false, "primary" : "config" }
        { "_id" : "test", "partitioned" : true, "primary" : "shard0000" }
                test.emails chunks:
                        { "id" : { $minKey : 1 } } -->> { "id" : { $maxKey : 1 }
 } on : shard0000 { "t" : 1000, "i" : 0 }
        { "_id" : "local", "partitioned" : false, "primary" : "shard0001" }

>

# 32ビット版は2GBまでしかつっこめないことに注意
32-bit-limitations

シャード1(shard0000), シャード2(shard0001)に直接接続しデータ件数を確認すると、シャード1にしかデータが登録されていない状態です。