AWSではレプリカセットでmongoセットアップを使用しています。セットアップの詳細:1つのプライマリノード:r3.8xlarge 4つのセカンダリノード:r5.xlarge Mongoバージョン:3.0.8(WiredTiger)データベースサイズ:358GB
このセットアップ用にmongoクラウドモニタリングを設定しました。ここにいくつかの統計があります:
Mongoプライマリネットワーク:350MB/S(イン:40MB/S、アウト:310MB/S、リクエスト数:5.32KB/S)プライマリノードでの平均1.1K接続プライマリで利用可能なチケット:読み取り:125、書き込み:100キュー:合計:15-20、読み取り:0-1、書き込み:15-20
その他のポイント:インスタンスのCPUとメモリの統計は、かなり制御されているように見えます。 800 GBのGP2 EBSボリューム(2400 IOPS)を使用しており、約2000 IOPSを消費しています。バーストバランスは、ほぼフル容量で利用できます。つまり、使い果たされていません。プライマリノードはr3.8xlargeタイプであるため、10ギガのネットワークがあります。 Ulimitsは次のように設定されます。
制限ソフト制限ハード制限単位最大CPU時間無制限無制限秒最大ファイルサイズ無制限無制限バイト最大データサイズ無制限無制限バイト最大スタックサイズ8388608無制限バイト最大コアファイルサイズ0無制限バイト最大常駐セット無制限無制限バイト最大プロセス64000 64000プロセス最大オープンファイル64000 64000ファイル最大ロックメモリ65536 65536バイト最大アドレススペース無制限無制限バイト最大ファイルロック無制限無制限ロック最大保留信号1967994 1967994信号最大msgqueueサイズ819200 819200バイト最大nice優先度0 0最大リアルタイムタイムアウト無制限無制限us
問題:Javaアプリケーションを使用してmongoにアクセスしており、多くのクエリが2〜4秒などのかなりの時間がかかっていることがわかります。プロファイリングを有効にし、最も遅いクエリをリストしました。更新オブジェクトのサンプルクエリが17000回インテントロックを取得し、それらを何回も生成しなければならないことがわかりました。それがインテントロックであるかどうかを理解できず、なぜ何回も生成する必要があるのでしょうか?インテントロックも他の操作を続行できないようにしますか?クエリが何回も生成する必要がある場合、ドキュメントレベルのロックの利点をどのように確認できますか?また、クエリの一部がタイムアウトしていることも確認しています(おそらくロックを長く待ちすぎて、最終的には無効になっています)。 )この問題をデバッグし、mongoのパフォーマンスを向上させる方法についてご案内いただけますか?
次に、サンプルクエリのプロファイラー出力を示します。
{
"op" : "update",
"ns" : "backend.Scores",
"query" : {
"channel.id" : "hkxj",
"metric" : "YVR",
"date" : ISODate("2018-11-20T10:00:00Z")
},
"updateobj" : {
"$set" : {
"channel" : {
"id" : "hkxj",
"failures" : 39,
"items" : [
{
"_id" : ObjectId("5bf3e434800075956f1"),
"image" : "http://images.abcd.com/something/wscoob.jpg",
"b_time" : ISODate("2018-11-26T19:24:00Z"),
"title" : "What's New ",
"id" : "fq969"
},
{
"_id" : ObjectId("5bf3e43f800075956f0"),
"image" : "http://images.abcd.com/something/w4citv2.jpg",
"broadcast_time" : ISODate("2018-11-26T20:24:00Z"),
"title" : "Let's End This",
"id" : "fsfgd"
}
]
},
"metric" : "YVR",
"date" : ISODate("2018-11-20T10:00:00Z")
},
"$setOnInsert" : {
"__v" : 0
}
},
"nscanned" : 0,
"nscannedObjects" : 2209900,
"nMatched" : 1,
"nModified" : 1,
"keyUpdates" : 0,
"writeConflicts" : 0,
"numYield" : 17264,
"locks" : {
"Global" : {
"acquireCount" : {
"r" : NumberLong(17266),
"w" : NumberLong(17266)
}
},
"Database" : {
"acquireCount" : {
"w" : NumberLong(17266)
}
},
"Collection" : {
"acquireCount" : {
"w" : NumberLong(17265)
}
},
"oplog" : {
"acquireCount" : {
"w" : NumberLong(1)
}
}
},
"millis" : 3864,
"execStats" : {
},
"ts" : ISODate("2018-11-20T10:40:25.104Z"),
"client" : "172.2.3.52",
"allUsers" : [ ],
"user" : ""
}
Javaアプリケーションを使用してmongoにアクセスしており、クエリの多くが2〜4秒などのかなりの時間を費やしていることがわかります。
提供される出力は、単一のドキュメントを更新するために2,209,900ドキュメントのコレクションスキャンを必要とするクエリを示しています。
_"nscanned" : 0,
"nscannedObjects" : 2209900,
"nMatched" : 1,
"nModified" : 1,
_
更新オブジェクトのサンプルクエリは、インテントロックを17000回取得し、それらを何回も生成する必要があることがわかりました。
コレクションスキャンは実行時間の長いクエリなので、他の操作がインターリーブできるようにするために複数回実行されます。参照: MongoDB Concurrency FAQ の 読み取りまたは書き込み操作でロックが発生しますか? 。
_{'channel.id': 1, metric: 1, date: 1}
_にサポートインデックスを追加すると、このクエリを大幅に改善できます。 クエリ説明オプション (つまりdb.Scores.find({..}).explain(true)
)を使用して、候補となるインデックスと使用法を確認します。
注:本番環境への影響を最小限に抑えるには、このインデックスを追加するときにバックグラウンドまたはローリングインデックスのビルドを実行する必要があります。 MongoDBのドキュメントには、手順と動作に関する詳細情報が含まれています: 人口のあるコレクションでのインデックス作成操作 。
プロファイリングを有効にし、最も遅いクエリをリストしました。
デプロイメントにすでにストレスがかかっている場合、 データベースプロファイラー を有効にしないように注意してください。これにより、追加の書き込み負荷が追加され、クエリの限られたサンプルのみがキャプチャされます(デフォルトでは、プロファイリングはデータベースごとに1MBの上限付きコレクションを使用します)。 。
遅いクエリ情報は既にMongoDBサーバーログで利用できるため、代わりにログベースのアプローチを採用します。 ServerFaultにいくつかの一般的なヒントがあります: MongoDBログのIXSCANおよびCOLLSCANについて 。
私が見つけたのは、ロックを取得する時間は2497196マイクロです。 (2497ミリ秒)ロックを取得するために必要な時間をどのように削減できますか?
ロックの取得にかなりの時間がかかる場合は、競合またはリソースの制約(たとえば、I/O)を示唆しています。遅いクエリをすべて最適化した場合は、より一般的なメトリックと、著しく遅いときに記録されるものを調べる必要があります。質問の説明では、まだリソースの制限について心配していないことが示唆されているため、ログと serverStatusメトリック がより焦点となる可能性があります。
この問題をデバッグし、mongoのパフォーマンスを向上させる方法についてご案内いただけますか?
全体的なパフォーマンスの調整は、ここでの回答よりもはるかに大きなトピックですが、推奨される開始点は次のとおりです。