見出し画像

MongoDBのShardingを試してみる

こんにちは。RGA(リアルグローブ・オートメーティッド)でインフラエンジニアをしている張です。

前回の記事では、MongoDBのReplicationをローカルで組んでみたのですが、今回はその続きでShardingを試してみたいと思います。

まずは、MongoDBのReplicationとShardingの違いを簡単に見ておきましょう。まず、Replicationは、3つのフォルダに1つのDBを同様に配置すると理解してもらってもいいと思います。つまり、このようなイメージになります。

これに対してShardingは、レプリカセットをさらにカットしてDBを分割し、別のマシンに配置すると考えることができます。つまり、下のようなイメージです。

構築イメージ

今回はShardが2つある構成を構築してみたいと思います。

アーキテクチャ図

​下記のように3つのVM(yuantst01, yuantst02, yuantst03)にShard、Config サーバ、Router(mongos)を配置するイメージです。

環境

環境は以下の通りです。

  • VM: ubuntu 20.04(LTS) 3台、メモリ4GB/ディスク20GB

    • yuantst01 (139.59.190.209)

    • yuantst02 (139.59.182.250)

    • yuantst03 (139.59.178.240)

  • MongoDB: 5.0.2 (各VMにインストール)

ドメイン指定

​前回はポート番号を分けることで1台のVM上でReplicationを作成しましたが、今回のShardingの作成ではポート番号は分けません。その代わりにDBを3つのVMに配置するこで、Shardを分割します。アーキテクチャ図を表で書くと、下記のようになります。

なお、レプリカセットには、メンバー(1つのPrimary, 2つのSecondary)があります。そのコンセプトを使って、下図のmember1,member3,member5をshard1(レプリカセットのようなもの)の3つメンバーとして作成しています(member2,member4,member6をshard2の3つメンバーとして作成すると理解していただいてもよいです)。

セットアップ手順

以下の手順でセットアップを行います。

  1. ドメイン設定(hosts追加)

  2. Shardingディレクトリを用意

  3. 1つ目のShardを作成して初期化

  4. Config サーバのレプリカセットを作成して初期化

  5. Router(mongos)を設定

  6. 大量データを作成(Shardキーをhashedで設定)

  7. 2つ目のShardを追加

  8. Router(mongos)に配置

それぞれについて見ていきましょう。

1. 各VMにhosts設定を追加

まずはhostsの設定です。3つのVMそれぞれに対して行います。

echo "139.59.190.209 yuantst01 member1.example.com member2.example.com" >> /etc/hosts
echo "139.59.182.250 yuantst02 member3.example.com member4.example.com" >> /etc/hosts
echo "139.59.178.240 yuantst03 member5.example.com member6.example.com" >> /etc/hosts
yuantst01
yuantst02
yuantst03

2. ディレクトリを用意

次に各VMにディレクトリを作成します。

mkdir -p /data/shard1/
mkdir -p /data/config/
mkdir -p /data/shard2/
mkdir -p /data/mongos/
yuantst01
yuantst02
yuantst03

3. 1つ目のシャードを設定

mongod --bind_ip 0.0.0.0 --replSet shard1 --dbpath /data/shard1 --logpath /data/shard1/mongod.log --port 27010 --fork --shardsvr --wiredTigerCacheSizeGB 1

引数の "--shardsvr --wiredTigerCacheSizeGB 1" は内部キャッシュの最大値を少なめに(1GB)設定する指定です。 なお、メモリ4GBのVMに対しては、デフォルトのキャッシュ値は1.5GBになります。
参考: storage.wiredTiger.engineConfig.cacheSizeGB

mongo member1.example.com:27010 --quiet
rs.initiate({ _id: "shard1", members: [{ _id: 0, host: "member1.example.com:27010"},{_id: 1, host: "member3.example.com:27010"},{_id: 2,host:"member5.example.com:27010"}]})

4. configサーバを設定

次にconfigサーバの設定を行います。

mongod --bind_ip 0.0.0.0 --replSet config --dbpath /data/config --logpath /data/config/mongod.log --port 27019 --fork --configsvr --wiredTigerCacheSizeGB 1
mongo member1.example.com:27019 --quiet
rs.initiate({ _id: "config", members: [{ _id: 0, host: "member1.example.com:27019"},{_id: 1, host: "member3.example.com:27019"},{_id: 2,host:"member5.example.com:27019"}]})

5. mongosを設定

mongosの設定です。

mongos --bind_ip 0.0.0.0 --logpath /data/mongos/mongos.log --port 27017 --fork --configdb config/member1.example.com:27019,member3.example.com:27019,member5.example.com:27019
mongo member1.example.com:27017 --quiet
sh.addShard("shard1/member1.example.com:27010,member3.example.com:27010,member5.example.com:27010");

追加が終わったら、詳細を確認します。

sh.status()

6. 大量なデータを作成

シャード(foo)用のCollection(bar)をデフォルトフィールドの_idをhashedというShard Keysとして作成します。

sh.enableSharding("foo");
sh.shardCollection("foo.bar",{_id: 'hashed'});

確認のため、10000件のデータを作成します。

use foo
for (var i=0; i<10000; i++) {
    db.bar.insert({i: i});
}

作成したCollectionの状況を確認します。

上図から、chunks: shard1 2...と返されていることがわかります。これは、barというコレクションが、2つのChunkで分割されていることを示しています。

どのように分割されているのかは、{"_id" : {"$minKey" : 1 }} -->> {"_id" : NumberLong(0) } on : shard1 Timestamp(1, 0)...と2つの形に分かれていることがわかります。

データの範囲を使ってShard キー指定する方法もありますが、hashed という形で試したかったので、デフォルトの_idフィールドで指定してます。目でデータを確認するとき、分かりづらいと思われがちですが、これが推奨されている方法です。

The field you choose as your hashed shard key should have a good cardinality, or large number of different values. Hashed keys are ideal for shard keys with fields that change monotonically like ObjectId values or timestamps. A good example of this is the default _id field, assuming it only contains ObjectId values.

出典: Hashed Sharding Shard Key
直訳すると、

ハッシュされたシャードキーとして選択するフィールドは、適切なcardinality、または多数の異なる値を持っている必要がある。ハッシュキーは、ObjectIdやタイムスタンプのように単調に変化するフィールドを持つシャードキーに最適。良い例は、ObjectIdのみが含まれていると仮定した場合のデフォルト_idフィールドです。

となります。

7. 2つ目のシャードを設定

1つ目のシャードを作成する方法と同様に、2つ目のシャードを設定します。

mongod --bind_ip 0.0.0.0 --replSet shard2 --dbpath /data/shard2 --logpath /data/shard2/mongod.log --port 27011 --fork --shardsvr --wiredTigerCacheSizeGB 1
mongo member2.example.com:27011 --quiet
rs.initiate({ _id: "shard2", members: [{ _id: 0, host: "member2.example.com:27011"},{_id: 1, host: "member4.example.com:27011"},{_id: 2,host:"member6.example.com:27011"}]})

8. 2つ目のシャードをmongosに追加

mongo member1.example.com:27017 --quiet
sh.addShard("shard2/member2.example.com:27011,member4.example.com:27011,member6.example.com:27011");
sh.status()

シャードfooのCollection(bar)を確認します。

sh.status()

別のVMでもシャーディングの状況も確認できます。yuantst02では、下のように表示されました。

実際、Collection(bar)のデータはどのように分割されているのかをGUI(Compass)で確認してみましょう。

Shard1は、10000件データのうち、4996件がこちらに格納されています。

Shard2は、10000件データのうち、5004件がこちらに格納されています。

無事にShardingで分割できていることが確認できました。

――――――――――――――――――――――――――――――――――

執筆者プロフィール:張 媛
文系出身、IT派遣会社で3年間オンプレ環境でのWeb開発しながら、Pythonなどの言語を自学し、GCPプレミアサービスパートナー会社に転職してクラウドでWeb開発を引き続き、DWH構築、データ可視化などを経験。
RGAでは、Azureでのインフラ構築、運用監視ツール開発、OSS導入支援などの業務に従事。

【ご案内】
ITシステム開発やITインフラ運用の効率化、高速化、品質向上、その他、情シス部門の働き方改革など、IT自動化導入がもたらすメリットは様々ございます。

IT業務の自動化にご興味・ご関心ございましたら、まずは一度、IT自動化の専門家リアルグローブ・オートメーティッド(RGA)にご相談ください!

お問合せは以下の窓口までお願いいたします。

【お問い合わせ窓口】
代表窓口:info@rg-automated.jp
URL: https://rg-automated.jp