web-dev-qa-db-ja.com

MongoDBが使用するメモリが多すぎる

私たちは数週間MongoDBを使用してきましたが、mongodbがメモリーを使いすぎている(はるかに多い)という傾向が見られますデータセット全体のサイズ+インデックスよりも大きい)。

私は既に この質問この質問 を読みましたが、私が直面している問題に対処しているようには見えません。彼らは実際にドキュメントですでに説明されていることを説明しています。

htopおよびshow dbsコマンドの結果を次に示します。

enter image description here

show dbs

MongodbはメモリマップドIOを使用することを知っているので、OSは基本的にメモリ内のキャッシュを処理し、mongodb 理論的には、別のプロセスが空きメモリを要求したときに、キャッシュされたメモリを手放す必要があります ですが、見て、それはしません。

OOMは他の重要なプロセスを殺し始めます。 postgres、redisなど(ご覧のとおり、この問題を克服するために、RAM= 183GBに増やしましたが、現在は機能しますが、かなり高価です。mongoは〜87GBのRAMを使用しており、ほぼデータセット全体のサイズの4倍)

そう、

  1. これだけのメモリ使用量は本当に予想され、正常ですか? (ドキュメントによると、WiredTigerは最大でRAM)の60%を使用しますが、データセットのサイズを考慮すると、86GBのRAM?)
  2. メモリ使用量が予想される場合でも、別のプロセスがより多くのメモリを要求し始めた場合に、mongoが割り当てられたメモリを解放しないのはなぜですか? RAMを増やしてシステムを完全に不安定にする前に、mongodb自体を含むさまざまな他の実行中のプロセスがLinux oomによって絶えず殺されていました。

よろしくお願いします!

29
SpiXel

さて、loicmathieuとjstellの手がかりをたどって少し掘り下げた後、これらは、WiredTigerストレージエンジンを使用してMongoDBについて見つけたものです。誰かが同じ質問に遭遇した場合は、ここに置いておきます。

私が言及したメモリ使用量スレッドはすべて2012-2014に属し、すべての以前のWiredTigerであり、元のMMAPV1ストレージエンジンの動作を記述しています個別のキャッシュや圧縮のサポートはありません。

WiredTiger キャッシュ設定 は、WiredTigerストレージエンジンによって直接使用されるメモリのサイズのみを制御します(mongodによって使用される合計メモリではありません)。 MongoDB/WiredTiger構成では、次のような他の多くのものがメモリを潜在的に使用しています。

  • WiredTigerはディスクストレージを圧縮しますが、メモリ内のデータは圧縮されません。

  • デフォルトでは、WiredTigerは各コミットでデータをfsyncしません。したがって、ログファイルもRAMメモリへの負担。I/ Oを効率的に使用するために、WiredTigerはI/O要求(キャッシュミス)をチャンク化することも述べられており、これもいくつかのRAM(実際にはダーティページ(変更/更新されたページ)の更新リストは Concurrent SkipList )に保存されます。

  • WiredTigerは、キャッシュに複数のバージョンのレコードを保持します(マルチバージョン同時実行制御、読み取り操作は、操作の前に最後にコミットされたバージョンにアクセスします)。

  • WiredTigerデータのチェックサムをキャッシュに保存します。

  • MongoDB自体は、開いている接続、集計、サーバーサイドコードなどを処理するためにメモリを消費します

これらの事実を考慮して、show dbs;は、データセットの圧縮サイズのみを表示するため、技術的には正しくありませんでした。

フルデータセットサイズを取得するには、次のコマンドを使用できます。

db.getSiblingDB('data_server').stats()
# OR
db.stats()

この結果は次のとおりです。

{
    "db" : "data_server",
    "collections" : 11,
    "objects" : 266565289,
    "avgObjSize" : 224.8413545621088,
    "dataSize" : 59934900658, # 60GBs
    "storageSize" : 22959984640,
    "numExtents" : 0,
    "indexes" : 41,
    "indexSize" : 7757348864, # 7.7GBs
    "ok" : 1
}

したがって、実際のデータセットのサイズとそのインデックスは、そのメモリの約68GBを使用しているようです。

これらすべてを考慮すると、メモリ使用量はかなり予想されていると思います。WidTigerのキャッシュサイズを制限しても問題ありません(前述のように)I/O操作をかなり効率的に処理するためです。

この問題を克服するために、OOMの問題も残っています。mongodbを取り出すための十分なリソースがなかったため、oom_score_adjを下げて、しばらくの間、重要なプロセスを強制終了することからのOOM(目的のプロセスを強制終了しないように OOMに伝えた意味 )。

23
SpiXel

文書

MongoDBの基本的なメモリの問題 と、この メモリの使用状況の確認に関する簡単な説明 をお読みください。

メモリ使用量の概要

コマンドdb.serverStatus()docs )は、メモリ使用量の概要を提供します。具体的には次のとおりです。

_> db.serverStatus().mem
{ "bits" : 64, "resident" : 27, "virtual" : 397, "supported" : true }

> db.serverStatus().tcmalloc
... not easy to read! ...

> db.serverStatus().tcmalloc.tcmalloc.formattedString
------------------------------------------------
MALLOC:        3416192 (    3.3 MiB) Bytes in use by application
MALLOC: +      4788224 (    4.6 MiB) Bytes in page heap freelist
MALLOC: +       366816 (    0.3 MiB) Bytes in central cache freelist
...
... a bunch of stats in an easier to read format ...
_

インデックスの大きさはどれくらいですか?

db.stats()はすべてのインデックスの合計サイズを表示できますが、db.myCollection.stats()を使用して単一のコレクションの詳細情報を取得することもできます

たとえば、次のコマンドはすべてのコレクションのインデックスのサイズを比較します

_> db.getCollectionNames().map(name => ({totalIndexSize: db.getCollection(name).stats().totalIndexSize, name: name})).sort((a, b) => a.totalIndexSize - b.totalIndexSize).forEach(printjson)
...
{ "totalIndexSize" : 696320, "name" : "smallCollection" }
{ "totalIndexSize" : 135536640, "name" : "bigCollection" }
{ "totalIndexSize" : 382681088, "name" : "hugeCollection" }
{ "totalIndexSize" : 511901696, "name" : "massiveCollection" }
_

これで、その大規模なコレクションの詳細を見て(== --- ==)、どのインデックスが最もコストが高いかを確認できます:

_> db.massiveCollection.stats().indexSizes
{
        "_id_" : 230862848,
        "groupId_1_userId_1" : 49971200,
        "createTime_1" : 180301824,
        "orderId_1" : 278528,
        "userId_1" : 50155520
}
_

これにより、節約が可能な場所をよりよく理解できます。

(この場合、createTimeを超えるインデックスがありました。これはかなり巨大で、ドキュメントごとに1つのエントリがありました。それがなくても問題ないと判断しました。)

4
joeytwiddle

JstellがWiredTigerを使用したMongoDBは使用可能なメモリの50%を使用するので、ここで問題はないと思います。サーバーのRAMを増やすと、より多くのメモリが必要になります。 。

DB +インデックスのサイズよりも大きい理由として、WiredTigerはディスク上のデータベースを圧縮し、スナップショットログを使用してドキュメントの変更を記録することにも注意してください。したがって、WiredTigerの実際のサイズは、show dbs * compression_ration +スナップショットログのサイズを使用したサイズです。したがって、正確な予想サイズを知ることはほとんど不可能です。

toppshtopなどのツールは、アプリケーションで実際に使用されているメモリを表示しなかったことにも注意してください。詳細については、このSOWの質問を参照してください。 https://stackoverflow.com/questions/131303/how-to-measure-actual-memory-usage-of-an-application-or-process

さて、あなたの問題に戻りましょう。同じホスト上で実行されている他のツールがあり、OOMがそれらを強制終了します。私はLinux OOMに精通していませんが、MongoDBまたは..のためにそれらを強制終了します(おそらく、Postgresがメモリを使いすぎたためにPostgresを強制終了します)。

とにかく、大きなMongoデータベースがある場合のベストプラクティスとして、他のデータベースと共有しているホストにデータベースをインストールしないでください。インストールすると、ここで説明するような問題が発生した場合に、多くの問題が発生します。本当にホストで問題を引き起こしている人。

4
loicmathieu