MongoDBのディスク使用量を理解する――領域割り当ての仕組みと最適化の判断基準

はじめに
MongoDBを使い始めたばかりの方にとって、そのディスク(スペース)使用量は一見すると分かりにくいものです。本記事では、MongoDBがどのようにディスク領域を割り当てるのか、そしてObjectRocketダッシュボードに表示される使用量情報をどう読み解けばよいのかを解説します。これにより、インスタンスのコンパクション(最適化)が必要なタイミングや、シャードを追加して利用可能領域を拡張すべきタイミングを適切に判断できるようになります。
検証環境:5GBシングルシャードのMediumインスタンス
まず、5GBのシャード1つで構成された真っさらなMediumインスタンスを用意します。このインスタンスに「ocean」という名前のデータベースを作成し、テストデータを投入しました。以下は、テストデータの追加といくつかのインデックス作成後のスペース使用状況です(本記事の説明のため、テストデータセットに対して意図的に大きなサイズになるインデックスを追加しています)。

315MiBのデータと254MiBのインデックスしかないのに、なぜ5GiBのシャードのうち2.1GiBも使用していることになるのでしょうか? これを説明するために、まずMongoDBがデータを「エクステント(extent)」と呼ばれる一連の領域としてディスクに保存する仕組みから見ていきましょう。
エクステントによるデータファイルの構造
ObjectRocketのインスタンスはsmallfilesオプション付きで稼働しているため、最初のエクステントは16MBで確保されます。エクステントは512MBに達するまで倍々にサイズが増えていき、それ以降はすべて512MBのファイルとして確保されます。したがって、例の「ocean」データベースのファイル構成は次のようになっています。
$ ls -lh ocean/
total 1.5G
-rw------- 1 mongodb mongodb 16M Aug 20 22:30 ocean.0
-rw------- 1 mongodb mongodb 32M Aug 20 20:44 ocean.1
-rw------- 1 mongodb mongodb 64M Aug 20 22:23 ocean.2
-rw------- 1 mongodb mongodb 128M Aug 20 22:30 ocean.3
-rw------- 1 mongodb mongodb 256M Aug 20 22:30 ocean.4
-rw------- 1 mongodb mongodb 512M Aug 20 22:30 ocean.5
-rw------- 1 mongodb mongodb 512M Aug 20 22:30 ocean.6
-rw------- 1 mongodb mongodb 16M Aug 20 22:30 ocean.ns
drwxr-xr-x 2 mongodb mongodb 4.0K Aug 20 22:30 _tmpこれらのエクステントには、データベースのデータとインデックスの両方が格納されます。MongoDBでは、あるエクステントにデータが書き込まれた時点で、次の論理的なエクステントが確保されます。つまり上記の構成では、ocean.6には現時点でデータがない可能性が高いものの、ocean.5が満杯になったときに備えて事前に確保されている状態です。そしてocean.6に何らかのデータが書き込まれた瞬間、新たな512MBのエクステントであるocean.7が再び事前確保されます。
また、MongoDBではデータを削除しても、コンパクションを実行しない限り領域は解放されません。そのため、削除が繰り返されたり、キーの追加などでドキュメントが元の格納場所よりも大きくなったりすると、時間の経過とともにデータファイルは断片化していきます。コンパクションでは、レプリカセットの別メンバーからデータを複製し、データファイルをゼロから再作成することで、これらのファイルをデフラグします。
ネームスペースファイル(.ns)
さらに16MBのファイルがネームスペースを格納しており、これがocean.nsファイルです。同じパターンがMongoDBインスタンス上の各データベースに対して繰り返されます。「ocean」データベースのほかに、シャード上には「admin」と「local」という2つのシステムデータベースが存在します。「admin」データベースにはすべてのデータベースユーザーの情報が格納されます(2.6.x以前は管理者ユーザー専用でした)。adminデータベースは小さくても、16MBのエクステント、事前確保された32MBのエクステント、16MBのネームスペースファイルを持っています。
localデータベースとoplog
もうひとつのシステムデータベースが「local」です。ObjectRocketが提供する各シャードは3メンバーのレプリカセットで構成されています。レプリカ間の同期を維持するため、MongoDBは各更新操作のログである「oplog」を保持しています。これは各レプリカで同期されており、セカンダリレプリカに適用すべき変更を追跡するために使われます。oplogは「local」データベース内のCapped Collectionとして存在します。ObjectRocketではoplogのサイズを一般的にシャードサイズの10%に設定しており、5GBのシャードの場合、oplogは500MBに設定されます。したがって「local」データベースは、16MBのエクステント、512MBのエクステント、16MBのネームスペースファイルで構成されます。
ジャーナル(journal)の役割
最後に、例のシャードにはもうひとつのハウスキーピング領域、ジャーナルがあります。ジャーナルはそれぞれ約128MBのファイルが1〜3個のセットです。書き込みが発生すると、MongoDBはまず更新内容をジャーナルに順次書き込みます。その後、バックグラウンドスレッドが定期的に(通常60秒ごとに)これらの更新を実際のデータファイル(前述のエクステント)へフラッシュします。この二重書き込みを行う理由は、実際のデータファイルへの書き込みに必要なシークと比べて、ジャーナルへのシーケンシャル書き込みのほうがはるかに高速だからです。変更を即座にジャーナルに書き込むことで、MongoDBはクラッシュ発生時のデータ復旧を保証でき、すべての書き込みがデータファイルへの反映を待つ必要もなくなります。現在のプライマリレプリカでは、2つのジャーナルファイルがアクティブになっているのが確認できます。
$ ls -lh journal/
total 273M
-rw------- 1 mongodb mongodb 149M Aug 20 22:26 j._1
-rw------- 1 mongodb mongodb 124M Aug 20 22:30 j._2MongoDBは、更新の頻度とバックグラウンドでのディスクフラッシュの頻度に応じて、これらのファイルを自動的にローテーションします。
ダッシュボードの使用量指標の読み方
ここまでMongoDBのディスク使用の仕組みを見てきましたが、これは冒頭で紹介したObjectRocketダッシュボードの使用量バーとどう対応しているのでしょうか?
- NS値(48MB):ocean、admin、localの3つのデータベースにおける16MBのネームスペースファイル3つ分の合計。
- Data値(315MiB):全データベース(システムデータベースを含む)の
db.stats()で報告されるdataSizeの合計。 - Index値(253.9MiB):全データベース(システムデータベースを含む)の
db.stats()で報告されるindexSizeの合計。 - Storage値(687.2MiB):全データベースのデータ+インデックスの合計に、削除によって未回収となっている領域を加えたもの。
- Total File値(2.0 GiB):プライマリレプリカで使用しているディスクの総量。Storage値とNS値の範囲に加え、事前確保されたエクステントも含みますが、ジャーナルの使用分は含みません。
コンパクションが必要かどうかの判断
これらの指標をもとに、簡単な計算でインスタンスが断片化していてコンパクションが必要かどうかを判断できます。断片化によって失われていると考えられる領域は、次の式で求めます。
100% −(Data + Indexes)/ Storage
例のインスタンスの場合、17%となります(100% −(315MiB Data + 253.9MiB Index)/ 687.2MiB Storage = 17%)。断片化率が20%に近づいたら、コンパクションの実行をおすすめします。
シャード追加の判断基準
もうひとつの計算は、全体的なスペース使用率に基づいてシャードを追加すべきかどうかの判断です。全体の使用率は次のように計算します。
(Total File /(プランサイズ × シャード数))× 100%
例のインスタンスでは40%となります((2 GiB / 5 GiB × 1シャード)× 100% = 40%)。一般的には、全体の使用率が80%に近づいたらシャードの追加を推奨しています。使用率が80%に達しそうだと気づいたら、サポートまでご連絡ください。インスタンスへのシャード追加をお手伝いします。
-
MongoDBの無駄なスペースを削減する戦略:フィールド名の短縮とネームストアによるトークン化
Appboyは、モバイルアプリ向けの世界有数のマーケティングオートメーションプラットフォームです。当社では毎月数十億規模のデータポイントを収集しており、顧客のモバイルアプリ上でのユーザーの行動を追跡し、その行動や属性情報に基づいて、メール、プッシュ通知、アプリ内メッセージによるターゲティングを可能にしています。データベース基盤の大部分はMongoDBが支えており、ObjectRocket上で複数のクラスタにまたがる数十のシャードを運用しています。短いフィールド名による基本戦略MongoDBにおける一般的なパフォーマンス最適化手法の一つが、ドキュメント内で短いフィールド名を使うことです。つまり、
-
Netflixのデータ使用量を制限する方法|スマホ・PC・テレビ別に徹底解説
「Netflix」と「エンターテインメント」は切っても切れない関係にあります。1997年に設立されたNetflixは、世界で最も人気のあるオンライン動画配信サービスの一つであり、スマートTV、ゲーム機、PC、スマートフォンなど、あらゆるデバイスでお気に入りの映画やドラマを楽しめるのが魅力です。一方で、インターネットは現代の生活に欠かせないインフラとなり、Wi-Fiでもモバイル回線でも、数多くのアプリやサービスが日々大量のデータを消費しています。特にNetflixでお気に入りの作品に没頭していると、気がつけばデータプランが急速に減ってしまった——そんな経験はありませんか?そこで本記事では、モバイ