web-dev-qa-db-ja.com

MongoDBのメモリ使用量

Mongoengineを備えたDjangoアプリがあります。これは、いくつかの集計クエリを十分頻繁に実行します。

主な問題はmongodがすべてのRAMを取得してからクラッシュするため、LRUが機能しないこと、-mongodがますます多くのメモリを取得しようとしていることです。

私のmongodbバージョンは3.2で、デフォルトのエンジンはMMAPv1です。ドキュメントが言うように、MMAPv1をキャッシュするには、dataSize + indexSizeのRAMが必要です。私の場合、それは約370MBです(dataSizeの場合は290、indexSizeの場合は〜80)。

これが私のdb.stats()です:

{
    "db" : "random_db",
    "collections" : 14,
    "objects" : 155613,
    "avgObjSize" : 1859.8720672437394,
    "dataSize" : 289420272,
    "storageSize" : 338821120,
    "numExtents" : 32,
    "indexes" : 22,
    "indexSize" : 82512192,
    "fileSize" : 1006632960,
    "nsSizeMB" : 16,
    "extentFreeList" : {
        "num" : 25,
        "totalSize" : 258314240
    },
    "dataFileVersion" : {
        "major" : 4,
        "minor" : 22
    },
    "ok" : 1
}

実際、1 GB RAMを取得し、別の1 GBのスワップファイルを作成しました。アプリが最初の集約クエリを実行すると(コレクションから50のドキュメントのみを取得)、mongod RAMの使用量は約300Mb(サービスを開始すると約50-100Mb)に増加し、約70までこのようなクエリが実行されるまで-すべての私のメモリ+スワップが終了し、mongodがクラッシュします。

集計の「$ match」に必要なすべてのインデックスを作成しました。必要に応じて、それらのいくつかをここに追加できます。

それで、私のデータベース全体が370Mbしかなく、データベースに150kのドキュメントしかない場合、2GBを超えるRAMを使用してキャッシュ内の〜4000のドキュメントが必要なのはなぜですか?私は何か間違っているのを知っています、質問は非常に単純ですが、それでもドキュメントで説明を見つけることができません。

ところで、これが私のdb.serverStatus.memです:

{
    "bits" : 64,
    "resident" : 112,//this value growth when queries executed
    "virtual" : 2523,
    "supported" : true,
    "mapped" : 1136,
    "mappedWithJournal" : 2272
}

つまり、私のmongodは、キャッシュ内のデータベース全体に対して2523Mbを超えることはできませんか?

1
vadimb

問題は、いくつか間違った仮定をすることです。以下にいくつかの修正があります

MongoDBはnot小さなリソース用に最適化されています

MongoDBは、大量のデータを取得するように特別に設計されています(クリックストリームの記録が最初のアプリケーションiircでした)。私が読むことができる限り、あなたのDjangoアプリはMongoDBと同じサーバー上にあります。ここでの問題は、あなたのDjangoアプリMongoDB側で行われる多くのクエリ/集計/書き込み操作で変換されます。したがって、DjangoおよびMongoDBは、特に高負荷時にリソースの競合を引き起こします) times。Djangoはスタックの最初なので、たとえばRAM現在、MongoDBが要求できないものです。リソースが不足しているためにMongoDBが何かを拒否し、要求がキャンセルされ、システムが何も実行していないように見えますが、実際にはアプリケーションの2つの部分が要求に最善を尽くしていたため、しかし、リソース不足のためにそうすることができませんでした。

正直に言うと、1 GBのインスタンスだけでMongoDBを実行するのは妥当ではありません。 Djangoアプリケーションを使用することは言うまでもありません。この設定では、少なくとも4GBのRAMが必要です、実際に負荷をかけるまで機能する可能性があります。比較のために、通常、ノードあたり32〜128 GBのRAM(データ、インデックス、およびその他のいくつかの要因に応じて)を推奨します。ストレージテクノロジーとしてSSDを使用するマシンもちろん、MongoDB専用です–もちろん、それに応じたデータ規模で。

"ワーキングセット"はしない(のみ)キャッシュを意味する

免責事項:残酷に簡略化され、用語がオフになっている可能性があります

MMAPv1はメモリマップファイルを使用します。すべての詳細はさておき、これはファイルがアドレス可能なメモリ範囲として扱われることを意味します。そのため、MongoDBが特定のドキュメントを読み取りたい場合は、読み取りたいメモリアドレスと範囲を使用します。そのメモリアドレスは、すでにRAMにあるか、ディスクから読み取る必要があります。または、ここに誤解があります。これは、ご想像のとおり、RAMに常駐しています。 、異なる部分ですが(Iirc、この状況で発生するのは、ポインターが参照するアドレスが変更されることです)。したがって、MongoDBがRAMにワーキングセットを持っているだけでなく、ファイルシステムキャッシュの一部なので、MongoDBには、ワーキングセットのみよりもさらに多くのRAMを必要とする部分があります。

ワーキングセットはではないメモリを消費する唯一のもの

  1. 実際、ジャーナリングのしくみは、MongoDBに必要なRAMを2倍にします。
  2. 各接続(および各ドライバーは基本的に接続プールを開くことを覚えています)は、1 MBのRAMが割り当てられます。
  3. 操作にはメモリが必要です。例として集計を取り上げましょう。それらは100MBのメモリ消費に制限されています-それだけで、RAMの10%、割り当て可能なメモリの5%になります。

ただし、MMAPv1を使用しているため、ジャーナリングをオフにしないでください! MMAPv1でのクラッシュリカバリには不可欠です。

結論

お使いのマシンはvastly RAMに関して十分にプロビジョニングされていません。予算が厳しい場合でも、RAMをそのマシンに追加する必要性を強調することはできません。少なくとも4GBをそのマシンに挿入します(物理的、つまりスワップしない) )、それがどうなるかを見てください。

ただし、この設定では常にDjangoとなり、MongoDBは必要最小限のときに最も多くのリソースを競合します。アプリケーションに同時ユーザーが比較的多い場合に注意してください。

1