はじめに
今回は、MongoDBのシャーディングについて説明します。
シャーディングとは、データを複数のサーバに分散させる機能です。今回は、最初にシャーディングのメリットを説明し、続けてシャーディングの概要、さらにシャーディングに登場する重要キーワードを解説します。2ページ目以降ではシャーディングの構築手順について解説します。
シャーディングはMongoDBの機能の中でも重要かつ複雑なもののひとつです。手元の環境で構築することが、シャーディングを理解する大きな助けになりますので、本記事を参考にぜひ構築してみてください。
シャーディングのメリット
シャーディングはMongoDBを水平スケーリングさせる機能で、以下のようなメリットをもたらします。
負荷分散による性能の向上
データを複数のサーバに分散させることにより、CPUやI/O負荷を分散させることが可能です。後述しますが、MongoDBはキーの範囲でデータを分散させます。適切なキー範囲を設定することにより、負荷を水平スケーリングさせることが可能となります。
リソース分散によるコストパフォーマンスの向上
近年、メモリやディスクの価格は大変安くなってきましたが、サイズの大きなモジュールほど価格が高く、また価格の上昇幅が大きくなることは変わりません。
メモリを例にあげますと、合計で64GBのメモリが必要になったとき、4GBメモリモジュール16枚の価格より16GBメモリモジュール4枚の価格の方が、一般的にコストがかかります。メモリもディスクも1台のサーバに積めるユニット数には制限があります。このような背景から、複数のサーバにデータを分散させることが、コストパフォーマンスの向上につながります。MongoDBではメモリが性能に直結するため、十分なサイズのメモリを確保することが推奨されています。
MongoDBのシャーディングの概要
シャーディングについて、データ分散と自動バランシングという2つの特徴を説明します。
シャードキーのレンジ(範囲)によるデータ分散
MongoDBのシャーディングはレンジパーティション方式を採用しています[1]。シャードキーを指定することで、各サーバに格納されるデータの範囲が決定されます。サーバ間で重複データは持たず、1つのデータが格納されるサーバはシャードキーの範囲によって1つに決定されます。
シャーディングのイメージを図で表すと、図1のようになります。図1に出てくる用語に関して後ほど説明しますので、まずは全体的なイメージを押さえてください。
自動バランシング
キー範囲の調整と、調整に伴うサーバ間のデータの移動まで全部MongoDBが行う自動バランシング[2]という機能を備えています。自動バランシングにより、サーバ間のデータの偏りをユーザが意識しなくてもよいように設計されています。また、新たにサーバを追加した場合も、同様にデータの移動を行い偏りがなくなるように自動調整します。
重要キーワードの説明
シャーディングに登場するキーワードに関して説明します。
シャード
実際にデータが格納されているmongodプロセスです。1つのドキュメントは1つのシャードに格納され、シャード間でデータの複製は行いません。必須ではありませんがレプリケーション構成とすることを推奨されています。
configサーバ
シャーディングのメタデータを管理しているmongodプロセスです。単一障害点となるので、複数のconfigサーバで構成することが推奨されています。
mongosサーバ
シャーディングにおけるルーティングプロセスです。シャードとクライアントを連携させます。必要があれば複数のmongosサーバをたてることが可能です。mongodプロセスではないので、状態やデータを持っていません。
シャードキー
データを分散する範囲のキーです。複数指定もできます。キー上のどの範囲のデータがどのシャードに格納されるかは、MongoDBが管理し、データの偏りによって自動調整を行います。シャーディングにおいて、シャードキーの設計が非常に重要になります。
チャンク
シャーディングにおけるチャンクとは、分散するデータの単位です。具体的には、あるコレクションの連続した範囲のデータで、複数のドキュメントとなります。チャンクの最大サイズに達すると分割され、シャードが持っているチャンク数に応じて必要ならば他のシャードに移動されます。チャンクの最大サイズは変更可能です。
これまでに説明したキーワードは、現時点では明確にイメージできなくても心配いりません。次のページ以降で実際にシャーディング環境を構築してみることで、理解を深めていきましょう。
シャーディングを試してみる(前半)
このページと次のページでは、実際にシャーディング構成を作ってみます。
今回は、1台の物理マシンにポートを分けて5つのサーバを立ち上げます。具体的にはconfigサーバ、mongosサーバ、および3つのシャード(node0、node1、node2)です。3つのmongodがそれぞれ別のシャードになります(図2参照)。
システムを構成するサーバの準備
ディレクトリ作成
まずデータディレクトリとログディレクトリを作成します。手順はすべてMongoDBを展開したディレクトリで行うことを想定しています。
シャードの起動
mongodコマンドに--shardsvrのオプションを指定することにより、このmongodがシャードになります。
configサーバ起動
mongodコマンドに--configsvrのオプションを指定することにより、このmongodがconfigサーバになります。
mongosサーバ起動
mongosコマンドによりmongosサーバを起動します(mongodではありません)。--configdbにてconfigサーバを指定します。mongosサーバはメモリ上にのみ存在するプロセスであるため、dbpathを指定する必要はありません。chunkSizeはチャンクのサイズをしています。デフォルトでは64Mですが、今回はチャンクが分割される動作を確認したいため、小さい1MBに設定します。
確認
psコマンドで5つのプロセスが見えればOKです。
mongosサーバにシャードの追加
mongoシェルで、mongosサーバのadminデータベースに接続します
sh.addShardメソッドでシャードを追加していきます。
「sh」というオブジェクトにはシャーディングの設定を簡単にするためのメソッドがあります。sh.help()を実行することにより使い方のヘルプを見ることができます。
sh.statusメソッドで追加したシャードが正しく追加されているかどうか確認します。
データの投入
続いて、mongosサーバ経由でデータを投入してみます。
mongosサーバに接続している状態で、logdbというデータベースを作ります。
続いて、logsというコレクションに10万件データを投入します。mongoシェルではjavascriptの文法が使えるため、forループによりデータを挿入しています。
最後にuidにインデックスを張ります。理由は、これからこのコレクションをシャード化する場合、シャードキーに対応するインデックスを作成しておく必要があるためです。
この時点ではまだシャーディングは有効になっていません。単純に最初のノードに10万件のデータが入っているだけです(図3参照)。
この状態を確認するには、mongoシェルにてmongosサーバのconfigデータベースの中身を見ればわかります。configデータベースのchunksコレクションにクエリをかけてみましょう。
シャーディングを試してみる(後半)
シャーディングの有効化
それではいよいよシャーディングを有効にして、データを分散させてみましょう。シャーディングを有効にするにはshオブジェクトのenableShardingメソッドにデータベース名を指定します。
次にsh.shardCollectionメソッドでシャード化するコレクションを指定します。第一引数は、(データベース名).(コレクション名)の文字列、第二引数はインデックスを作成するときのハッシュです。
シャーディングの状態確認
ここでsh.statusメソッドでシャーディングの状態を表示すると、3つのシャードサーバにそれぞれチャンクができている様子がわかります。
上記の出力では、shard0000のチャンク数が8つ、shard0001のチャンク数が1つ、そしてshard0002のチャンク数が1つとなっています。
このようにチャンクの数が偏っているのは、まだデータが移動中であるためです。しばらくした後に、もう一度sh.statusを実行してください。
しばらく時間がたつと、チャンクの数が3,3,4と均等になっていることがわかります(図4参照)。
また、出力の後半に各チャンクに入っているシャードキーの範囲が出力されています。
上記の例では、shard0002のチャンクには、uidの範囲が10083≦uid<20166であるコレクションが格納されていることがわかります。
[参考]$minKeyはすべての値よりも小さいとみなされ、$maxKeyはすべての値よりも大きいとみなされます。
また、別の確認方法として、mongosサーバのconfigテーブルを見る方法もあります。
各シャードサーバの状態確認
シャーディングされている状態で、各シャードサーバがどのようになっているか確認しましょう。やり方は簡単で、各シャードサーバにmongoシェルで接続すればOKです。まずnode1にアクセスしてみましょう。
このように、各シャードサーバに入っているコレクションの数を参照することができます。また、findメソッドなどで普通にコレクションを参照することもできます。他のシャードサーバでも同じです。
次回のテーマ
今回はMongoDBのデータ分散機能であるシャーディングについて紹介しました。シャーディング機能を使用することにより、負荷分散とリソース分散によるコスト削減を実現できます。また、自動バランシングというMongoDBの特徴的な機能も紹介しました。
次回は、前回の記事で紹介したレプリケーションと今回紹介したシャーディングを組み合わせた構成を紹介します。