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を超えることはできませんか?
問題は、いくつか間違った仮定をすることです。以下にいくつかの修正があります
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を必要とする部分があります。
ただし、MMAPv1を使用しているため、ジャーナリングをオフにしないでください! MMAPv1でのクラッシュリカバリには不可欠です。
お使いのマシンはvastly RAMに関して十分にプロビジョニングされていません。予算が厳しい場合でも、RAMをそのマシンに追加する必要性を強調することはできません。少なくとも4GBをそのマシンに挿入します(物理的、つまりスワップしない) )、それがどうなるかを見てください。
ただし、この設定では常にDjangoとなり、MongoDBは必要最小限のときに最も多くのリソースを競合します。アプリケーションに同時ユーザーが比較的多い場合に注意してください。