使用しているメモリが多すぎるMongoDB


28

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

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

以下は、htopおよびshow dbsコマンドの結果です。

ここに画像の説明を入力してください

dbsを示して下さい

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

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

そう、

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

ありがとう!


4
mongodb.com/presentations/…など、WiredTigerの内部に関するプレゼンテーションのいくつかは、光を放つかもしれません。物理RAMの50%のデフォルトの使用量は、専用のMongoDBホストで必要とされる可能性があるものの推測にすぎず、多くの場合、変更する必要があると予想しています。FWIW、cacheSizeGBの設定がmongoを「制限」しているとは思わない-オプションがあるため、展開を制御できます。キャッシュに必要なメモリmongoの量を決定するには、予想されるサーバー負荷の下でサーバーキャッシュの統計を監視する必要があります。

回答:


23

さて、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のメモリを消費しているようです。

これらすべてを考慮すると、メモリ使用量はかなり予想されると思いますが、I / O操作をかなり効率的に処理するので(上記のように)、WiredTigerキャッシュサイズを制限しても大丈夫です。

OOMの問題も残っています。この問題を克服するために、mongodbを取り出すのに十分なリソースがなかったため、OOM が当面重要なプロセスを強制終了しないようにoom_score_adjを下げました(つまり、必要なプロセス)。


同様の問題があります。MongoDBはRAMを使い続けます。同様の割合。oom_score_adj 解決策はあなたが思いついた最高のものでしたか?
ハルター

@Hartatorええ、wiredtigerのcacheSizeを減らし、インデックスとインデックス作成ポリシーの管理により多くの労力を注ぎ、最後に、面倒なことのためにoom_score_adjを減らしました。
SpiXel

4

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

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

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

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

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


4

ドキュメント

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つのエントリがあり、それなしでも生きることができると判断しました。)


インデックスには大きなメモリコストがかかりますか?
マティアスリュックガードローレンツェン

@MathiasLykkegaardLorenzenこれは、サーバーのRAMを基準にして、インデックスを作成したフィールドの一意の値の数に依存します。私たちの場合、createTimeインデックスはドキュメントごとに一意であり、そのコレクションは膨大であるため、問題がありました。一意の値が少ないため(値はクラスター化されていたため)、他のフィールドのインデックス付けは問題ありませんでした。
joeytwiddle
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.