fbpx

よくある質問

MongoDB FAQ #6: ストレージ


1. ストレージエンジンの基本

ストレージエンジンとは何でしょうか?

ストレージエンジンとは、メモリとディスクの両方で、データがどのように格納されているかの管理を担うデータベースの機能の一部です。データベースの多くは、複数のストレージエンジンをサポートしており、特定のワークロードに対しては特定のエンジンがより優れたパフォーマンスを発揮する場合があります。例えば、読込み負荷の高いワークロードでより優れたパフォーマンスを提供するストレージエンジンもあれば、書込み操作に対してより高いスループットをサポートするストレージエンジンもあります。

こちらもご参照ください: Storage Engines

2. レプリカセット内でストレージエンジンを混在させることはできますか?

はい。異なるストレージエンジンを使用するレプリカセットメンバを持つことができます。

これらのマルチストレージエンジンのデプロイを設計する時に、次の点を考慮してください。

  • 各メンバのoplog は、異なるストレージエンジン間のスループットの差異を考慮して、違うサイズにする必要があるかもしれません。
  • もしMongoDBからデータファイルを取り込んでバックアップする場合、バックアップからの復元はより複雑になります。従って、各ストレージエンジンごとにバックアップを保存する必要があります。

3. WiredTiger ストレージエンジン

既存のデプロイをWiredTigerにアップグレードすることはできますか?

はい。 次をご参照ください

WiredTiger はどの程度の圧縮率を提供していますか?

圧縮データと非圧縮データの比率は、使用するデータと圧縮ライブラリによって決まります。デフォルトでは、WiredTiger のコレクションデータは Snappy block compression を使用しています。zlib compression も使用可能です。また、インデックスは prefix compression をデフォルトで使用しています。

WiredTiger 内部キャッシュはどれぐらいのサイズに設定すれば良いですか?

WiredTiger を使用する場合、MongoDB はファイルシステムキャッシュとWiredTiger 内部キャッシュの両方を活用します。3.4以降では、WiredTiger 内部キャッシュは以下の2つのうちでより大きい方を使用します:

  • (RAM - 1 GB) の50%
  • 256MB

例えば、4GBのRAMを搭載したシステムでは、WiredTigerキャッシュは1.5GB(=0.5*(4GB-1GB))となります。一方1.25GBのRAMを搭載したシステム上のWiredTigerキャッシュは256MBとなります。なぜなら(0.5*(1.25GB-1GB))=128MBは256MBよりも少なくなるからです。

WiredTiger は 全てのコレクションには Snappy block compression を、そして全てのインデックスには prefix compression をデフォルトで使用します。圧縮のデフォルトは、グローバルレベルで設定可能です。また、コレクションおよびインデックス作成時に、コレクション毎、インデックス毎でも設定できます。

WiredTiger 内部キャッシュ内のデータとディスク上のデータのフォーマットは、それぞれ異なる内部表現が使用されています

  • ファイルシステムキャッシュ内のデータは、データファイル圧縮の利点を含めて、オンディスクフォーマットと同じです。WiredTigerが生成したオンディスクキャッシュは、OSでも使用され、ディスクIOの低減を期待することができます。
  • WiredTiger 内部キャッシュでロードされたインデックスはオンディスクフォーマットとは異なる内部データ表現を保持しますが、RAM 使用量を抑えるための index prefix compression の恩恵は受けられます。Index prefix compression はインデックスされたフィールドから一般的な prefixes の重複排除を行います。
  • WiredTiger 内部キャッシュ内のコレクションデータは圧縮されておらず、オンディスクフォーマットとは異なる内部表現 を使用しています。Block compression を使用することでオンディスクストレージを大幅に節約できますが、サーバーからの操作を可能にするため、データは使用する前にサーバによって圧縮が解除されます。

MongoDB は、ファイルシステムキャッシュを介すことによって、WiredTiger キャッシュもしくは他のプロセスによって使用されていない全てのメモリを自動的に使用します。

WiredTiger 内部キャッシュのサイズを調整するには、こちらをご参照ください: storage.wiredTiger.engineConfig.cacheSizeGB および --wiredTigerCacheSizeGB (WiredTiger 内部キャッシュのサイズをデフォルト値より多い値に設定することは避けてください。)

注:

WiredTiger 内部キャッシュのサイズは、storage.wiredTiger.engineConfig.cacheSizeGB で制限されています。OS は使用可能な状態のメモリをファイルシステムキャッシュ用に使用します。これにより圧縮されたMongoDBデータファイルがメモリに保持されます。加えて、OSは使用可能な状態のRAM をファイルシステムブロックおよびファイルシステムキャッシュをバッファーするために使用します。

もしOSのバッファ量を増やしたい場合は、WiredTiger内部キャッシュのサイズを小さくしなければならない場合があります。

WiredTiger 内部キャッシュのサイズ値のデフォルトは、マシン当たり一つのmongod インスタンスがあると仮定しています。もし1台のマシンが複数のMongoDB インスタンスを保持している場合、他のmongod インスタンスを 許容させるために設定を下げなくてはなりません。

システム内の利用可能なRAM全てへのアクセスがないコンテナ(例:lxc、cgroups、Docker 等 )で mongod を実行する場合:storage.wiredTiger.engineConfig.cacheSizeGB をコンテナ内の利用可能なRAM の量以下の値に設定しなくてはなりません。正確な値は、コンテナ内で実行中の他のプロセスに依ります。

キャッシュおよびキャッシュエビクションの統計は、serverStatusコマンドから返された wiredTiger.cache フィールドで閲覧可能です。

WiredTiger のディスク書込み頻度はどの程度ですか?

この部分は3.6バージョンで変更されました: MongoDB は60秒のインターバルでチェックポイントを作成する(スナップショットデータをディスクに書き込む、等)ようにWiredTiger を設定します。

ジャーナルデータに関しては、MongoDB は以下のインターバルもしくは条件に基づいてディスクへ書込みます。

  • 3.2バージョンで追加:50ミリ秒ごと
  • 3.6バージョンにて変更: WiredTigerは60秒間隔でユーザーデータのチェックポイントを作成します
  • 書込み操作のなかに j: true の書込み強制指定がある場合、WiredTiger はWiredTiger ジャーナルの同期を強制的に実施します
  • MongoDB が100MBのサイズ制限があるジャーナルファイルを使用しているため、WiredTiger はおよそ100MBごとに新規ジャーナルファイルを作成します。WiredTiger が新規ジャーナルファイルを作成する場合、WiredTiger は以前のジャーナルファイルを同期します。

WiredTiger 内のディスク(空き)領域を回収するにはどうしたら良いでしょうか?

WiredTiger ストレージエンジンはドキュメント削除の際にデータファイル内の空レコードのリストを保持しています。この空き領域はWiredTiger によって再利用可能ですが、 特別な場合を除き、OSに返還されません。

WiredTiger によって再利用可能な空き領域の量は、db.collection.stats() の出力内の、wiredTiger.block-manager.file bytes available for reuseに記録されています。

データファイルのデフラグによって、WiredTiger ストレージエンジンがこの空き領域をOSに解放できるようになります。これは compact コマンドで実施可能です。この動作および他の考慮すべき事柄に関する更なる情報はこちら( compact )をご参照ください。

4. MMAPv1 ストレージエンジン

メモリマップファイルとは何ですか?

メモリマップファイルとは、mmap()システムコールのやり方でOSがメモリに置くデータのファイルのことです。したがって、mmap() はバーチャルメモリの領域にファイルをマップします。MongoDB においてメモリマップファイルは MMAPv1 ストレージエンジンの重要な要素です。メモリマップファイルを使用することで、 MongoDB は データファイルのコンテンツがあたかもメモリにあるかのように扱うことができます。これによって MongoDB のデータへのアクセス方法および操作方法が大変高速でシンプルになります。

メモリマップファイルはどのように機能しているのですか?

MongoDB は全てのデータの管理およびやり取りにメモリマップファイルを使用します。

メモリマップはファイルをVirtual Memory にバイト単位でダイレクトにアサインします。MongoDB メモリはデータファイルをドキュメントにアクセスするようにメモリにマップします。アクセスされていないデータはメモリにマップされません。

マップされた後、ファイルとメモリの関係性によって、MongoDB はファイル内のデータにあたかもそれがメモリにあるように操作ができるようになります。

MMAPv1のディスク書込み頻度はどの程度ですか?

MMAPv1 ストレージエンジンのデフォルトの設定では、MongoDB は60秒毎にデータファイルのディスク書込みを行い、約100ミリ秒毎にジャーナルファイルを書込みます。

データファイル書込みの頻度を変更するには、storage.syncPeriodSecs設定を使用してください。ジャーナルファイルについては、storage.journal.commitIntervalMs 設定をご参照ください。

これらの値は、MongoDBがデータファイルもしくはジャーナルファイルを書き込む際、書き込み完了までの最大時間を表します。多くの場合、MongoDB およびOSはより頻繁にデータをディスクにフラッシュしますので、前述の値は理論上の最大値です。

データディレクトリ内のファイルのサイズが、データベースのサイズより大きいのはなぜですか?

デフォルト設定で /data/dbディレクトリである、データディレクトリのデータファイルは、データベースに挿入されたデータセットより大きいかもしれません。その場合は次のような原因が考えられます:

事前に配置されたデータファイル

MongoDB は、ファイルシステムのフラグメンテーションを避けるためにデータファイルを事前に配置します。よってこれらのファイルはデータのサイズを常に反映するという訳ではありません。

これらのファイルサイズを減らすには storage.mmapv1.smallFiles が有効です。これはディスク上に小規模なデータベースが多くある場合に便利です。

Oplog

このmongod がレプリカセットのメンバーの場合、データディレクトリは oplog.rs ファイルを含みます。これは local データベースに事前配置された capped collection です。

デフォルトの配置は、64bitオペレーティングシステム環境で使用する場合のディスク領域の約5%です。多くの場合、oplog をリサイズする必要はありません。詳細はこちら( Oplog Sizing )をご参照ください。

ジャーナル

MongoDB が書込み操作をデータベースに適用する前に、ジャーナルファイルがディスクに書込み操作を保管します。ジャーナルファイルはデータディレクトリ内に存在します。こちら( Journaling )をご参照ください。

空のレコード

MMAPv1 ストレージエンジンはドキュメントおよびコレクションを削除の際に、データファイル内の空レコードのリストを保持します。この空き領域は同一データベース内の新規レコードの配置に再利用可能ですが、デフォルトではOSに返還されません。

データのデフラグによって、MMAPv1ストレージエンジンが空き領域をより効果的に再利用できるようになります。デフラグにはcompact コマンドを利用してください。compact コマンド実行用に空きディスク領域が最大2ギガ必要です。ディスク領域の残りが少ない場合はcompact を使用しないでください。この動作および他の考慮すべき事柄に関する更なる情報はこちら( compact )をご参照ください。

compact はコレクション内のMongoDB データファイルのデフラグのみを行い、OSにディスク領域を返還することはありません。OSにディスク領域を変換する方法はこちら( ディスク(空き)領域を回収するにはどうしたら良いでしょうか? )をご参照ください。 

ディスク(空き)領域を回収するにはどうしたら良いでしょうか?

注:

MongoDB が解放された領域を再利用するのにディスク領域の回収は不要です。解放された領域の再利用に関してはこちら( 空きレコード )をご参照ください。

レプリカセットのセカンダリメンバー用に、メンバーの再同期を行うことができます。まずセカンダリメンバーを再同期用に停止、次にメンバーのデータディレクトリから全データおよびサブディレクトリ削除、そしてセカンダリメンバーの再起動という手順です。詳細はこちら( Resync a Member of a Replica Set: レプリカセットメンバーの再同期 )をご参照ください。 

dropDatabase 経由で、使用していないデータベースをドロップすることで、関連データも削除されディスク領域を解放します。

ワーキングセットとは何ですか?

通常の操作でアプリケーションが使用するデータの合計を表します。多くの場合、これはデータサイズ合計のサブセットですが、具体的なワーキングセットのサイズは実際のデータベースの使用状況によります。

MongoDB がコレクション内の全ドキュメントをスキャンする必要があるクエリを実行すると、ワーキングセットは全ドキュメントが含まれるように拡張されます。これは、物理メモリサイズにもよりますが、ワーキングセット内のドキュメントが「ページアウト」する原因、もしくはOSによって物理メモリから削除される原因になり得ます。これらのドキュメントにMongoDB が再度アクセスするする必要が発生した場合、MongoDB がhard page fault を引き起こすでしょう。

最良のパフォーマンスのためには、大半のアクティブセットがRAM に入りきる必要があります。

ページフォルトとは何ですか?

MMAPv1 ストレージエンジンでは、MongoDB が物理メモリに配置されていないデータファイルの一部のデータを読込みもしくは書込みすることでpage faults が生じます。対照的に、OS ページフォルトは、物理メモリを使い切ってしまい、物理メモリのページがディスクにスワップされたときに起きます。

空きメモリがある場合、OSはディスク上でページを見つけメモリに直接ロードすることができます。しかしながら、空きメモリがない場合、OSは:

  • メモリ内で既に不要となったページを見つけ、ディスクにページを書き込みます
  • リクエストされたページをディスクから読込みメモリにロードします

アクティブなシステム上でのこのプロセスは、既にメモリにあるページを読み込むのと比較するととても時間がかかります。

詳細はこちら( Page Faults )をご参照ください。

ソフトページフォルトとハードページフォルトの違いは何ですか?

ページフォルトは、MMAPストレージエンジン付きのMongoDB がメモリで今アクティブでないデータにアクセスする必要がある場合に起こります。“ハード”ページフォルトは、MongoDB がデータアクセスのためにディスクにアクセスしなければならない時におきます。対照的に”soft”ページフォルトは単にOSのファイルキャッシュなどのあるリストから他のリストにメモリページを移動させることを指します。

詳細はこちら( Page Faults )をご参照ください。

5. 更新中のドキュメントの移動を防ぐために、手動でドキュメントをパディングすることはできますか?

この部分は3.0.0で変更されました。

MMAPv1ストレージエンジンでは、更新によってドキュメントサイズが大きくなった場合、ディスク上でドキュメントが移動する場合があります。ドキュメントの移動を最小化するために、MongoDB はpadding を使用します。

ユーザが手動でパディングを行うべきではありません。MongoDBはデフォルトで2のべき乗のサイズでドキュメントをパディングしてアロケーションします。2のべき乗のサイズによるアロケーションは、MongoDB がドキュメントスペースを2のべき乗サイズで配置することを保証します。これは、MongoDB がドキュメント削除・リロケーションによって生まれた空き領域を効率的に再利用することをサポートし、多くの場合、再配置の発生を減らすことにもつながります。

しかしながら、ドキュメントを手動でパディングしなければならない場合、次の例のように、ドキュメントにテンポラリーフィールドを追加してフィールドを$unsetしてください。

警告:

キャップされたコレクション内でドキュメントを手動でパディングしないでください。キャップされたコレクション内でドキュメントを手動でパディングすると、レプリケーションを損ないかねません。また、MongoDB インスタンスを再同期すると、パディングは保存されません。

var myTempPadding = [ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"];
db.myCollection.insert( { _id: 5, paddingField: myTempPadding } );
db.myCollection.update( { _id: 5 },
{ $unset: { paddingField: "" } }
)
db.myCollection.update( { _id: 5 },
{ $set: { realField: "Some text that I might have needed padding for" } }
)

 こちらもご参照ください:Record Allocation Strategies

6. データストレージ診断

コレクションのサイズをどうしたら確認することができますか?

データサイズを含むコレクションの統計データを参照するには、 mongo shell から db.collection.stats() メソッドを使用してください。次の例はorders コレクションへdb.collection.stats() を呼び出します。

db.orders.stats();

 MongoDB はコレクションの具体的なサイズを返す次のメソッドも提供します:

次のスクリプトは各データベースの統計を出力します。

db.adminCommand("listDatabases").databases.forEach(function (d) {
mdb = db.getSiblingDB(d.name);
printjson(mdb.stats());
})

 次のスクリプトは各データベース内のコレクション毎の統計を出力します:

db.adminCommand("listDatabases").databases.forEach(function (d) {
mdb = db.getSiblingDB(d.name);
mdb.getCollectionNames().forEach(function(c) {

s = mdb[c].stats();
printjson(s);
})
})

コレクションに対するインデックスをどうしたら確認することができますか?

コレクションに割り当てられたインデックスを確認するには、db.collection.stats() メソッドを使用し、返されたドキュメントのindexSizes を確認してください。

データベースのストレージ使用状況の情報を確認することができますか?

mongo shell のdb.stats() メソッドは「アクティブ」なデータベースの現状を返します。返されるフィールドの説明はこちら(dbStats Output)をご参照ください。