ApsaraDB for MongoDB インスタンスの CPU 使用率が 100% 近くまで高騰すると、読み取り/書き込み操作が遅くなり、ビジネス運用に支障をきたします。以下の診断手順に従って、根本原因を特定し、解決してください。
実行中の操作の確認
mongo シェルを使用してインスタンスに接続します。接続手順はインスタンスのアーキテクチャによって異なります。
db.currentOp() を実行して、インスタンスで現在実行中のすべての操作を一覧表示します。
db.currentOp()出力例:
{
"desc" : "conn632530",
"threadId" : "140298196924160",
"connectionId" : 632530,
"client" : "11.192.159.236:57052",
"active" : true,
"opid" : 1008837885,
"secs_running" : 0,
"microsecs_running" : NumberLong(70),
"op" : "update",
"ns" : "mygame.players",
"query" : {
"uid" : NumberLong(31577677)
},
"numYields" : 0,
"locks" : {
"Global" : "w",
"Database" : "w",
"Collection" : "w"
},
....
}以下のフィールドに注目して、問題のある操作を特定します。
| フィールド | 説明 | 対応すべきケース |
|---|---|---|
client | リクエストを送信したクライアント | これを使用してリクエストのソースをトレースします |
opid | 一意の操作 ID | 必要に応じて db.killOp(opid) を実行して操作を停止します |
secs_running | 操作が実行されている時間 (秒単位) | 予期せず値が大きい操作を調査します |
microsecs_running | 操作が実行されている時間 (マイクロ秒単位) | 予期せず値が大きい操作を調査します |
ns | スキャン対象の名前空間 (コレクション) | スロークエリログと照合してホットコレクションを見つけます |
op | 操作タイプ:query、insert、update、または delete | — |
locks | 操作のロック情報 | 詳細については、「よくある質問:同時実行数 |
「db.currentOp()」の詳細については、db.currentOp()をご参照ください。
CPU 使用率が急上昇する一般的な原因は、コレクション全体のスキャンなどの運用保守 (O&M) 操作が、通常のワークロードと並行して実行されることです。db.currentOp() の結果に、予期しない大きな secs_running 値を持つ操作が表示された場合は、その操作を停止します。
db.killOp(<opid>)<opid> を db.currentOp() の出力にある opid フィールドの値に置き換えてください。詳細については、「db.killOp()」をご参照ください。
スロークエリログの分析
アプリケーションの起動直後に CPU 使用率が上昇し、高いまま維持されるものの、db.currentOp() には明らかに問題のある操作が表示されない場合、原因は時間とともに蓄積されたスロークエリのパターンである可能性が高いです。
ApsaraDB for MongoDB コンソールでスロークエリログを表示します。詳細については、「スロークエリログの表示」をご参照ください。
スロークエリログのエントリ例は次のようになります。
{
"atype": "slowOp",
"param": {
"op": "query",
"ns": "abbott_analysis.uaidScanInfo",
"query": {
"find": "uaidScanInfo",
"filter": {
"dateType": 2,
"companyCode": "GMP"
},
"ntoreturn": -1,
"sort": {
"scanDateTime": -1
}
},
"keysExamined": 0,
"docsExamined": 2181021,
"hasSortStage": true,
"cursorExhausted": true,
"numYield": 17059,
"locks": { ... },
"nreturned": 0,
"responseLength": 20,
"millis": 4878,
"planSummary": "COLLSCAN"
},
"result": "OK"
}スロークエリログで以下のパターンを探します。
コレクション全体のスキャン (COLLSCAN、docsExamined)
planSummary: COLLSCAN は、クエリがインデックスを使用せずにコレクション全体をスキャンしたことを意味します。docsExamined フィールドはスキャンされたドキュメント数を示し、この数値が高いほど、クエリが消費した CPU が多くなります。
この問題を解決するには、クエリ対象のフィールドにインデックスを作成します。
db.<collection>.createIndex({ <field>: 1 })非効率なインデックス (IXSCAN、keysExamined)
クエリがインデックスを使用すると、planSummary には IXSCAN と表示されます。keysExamined フィールドは、スキャンされたインデックスキーの数を示します。この値が大きいほど、リクエストが占有する CPU リソースが多くなります。
インデックスの選択性の例
x フィールドが 2 つの値 (1 または 2) しか持たない一方、y フィールドがはるかに広い範囲 (1 から 100000) を持つコレクションを考えます。クエリ { x: 1, y: 2 } の場合:
{ x: 1, y: 1 }
{ x: 1, y: 2 }
...
{ x: 1, y: 100000 }
{ x: 2, y: 1 }
...| インデックス | 選択性 | 理由 |
|---|---|---|
db.createIndex({ x: 1 }) | 不良 | コレクションの半分が同じ x の値を共有しているため |
db.createIndex({ x: 1, y: 1 }) | 不良 | 先頭フィールド x は依然として低選択性です |
db.createIndex({ y: 1 }) | 良好 | y の値の範囲が広く、同じ値を共有するドキュメントが少ないため |
db.createIndex({ y: 1, x: 1 }) | 良好 | 先頭フィールドの y がほとんどのドキュメントを即座に除外するため |
選択性の高いフィールドを先にインデックス付けしてください。詳細については、「MongoDB インデックスの設計原則」および「複合インデックス」をご参照ください。
インデックスが過剰にあると、書き込みおよび更新のパフォーマンスに影響します。ご利用のアプリケーションに多数の書き込み操作が含まれており、インデックスを使用している場合、アプリケーションのパフォーマンスが影響を受ける可能性があります。書き込みパフォーマンスも低下している場合は、未使用のインデックスを監査して削除してください。
メモリ内ソート (SORT、hasSortStage)
hasSortStage: true は、ソート順を満たすインデックスがなかったため、インスタンスがクエリ結果をメモリ内でソートしたことを意味します。大規模な結果セットに対するメモリ内ソートは、大量の CPU を消費します。
スロークエリログにキーワード SORT が含まれている場合は、ソート句で使用されているフィールドにインデックスを作成します。
db.<collection>.createIndex({ <sort-field>: 1 })その他の CPU 使用率が高い操作
インデックスの作成や aggregation パイプライン (トラバーサル、フィルタリング、更新、ソートを組み合わせたもの) も、高い CPU 使用率の原因となる可能性があります。同じ診断アプローチを適用し、スロークエリログの docsExamined、keysExamined、hasSortStage、planSummary を確認してください。
サービスキャパシティの評価
すべてのクエリが適切なインデックスを使用していても CPU 使用率が高いままである場合、インスタンスがキャパシティの上限に達している可能性があります。
モニタリングデータを確認して、リソース使用量のパターンを把握します。詳細については、「モニタリングデータの表示」および「ノードモニタリング (旧基本モニタリング)」をご参照ください。
現在のインスタンス仕様がワークロードの要件を満たしているか確認します。必要に応じて、インスタンスのスペックをアップグレードします。詳細については、「インスタンスの構成変更」または「レプリカセットインスタンスの構成変更」をご参照ください。
クイックリファレンス
| コマンド | 目的 |
|---|---|
db.currentOp() | インスタンスで現在実行中のすべての操作を一覧表示します |
db.killOp(<opid>) | 操作 ID を指定して特定の操作を停止します |
| コンソールでスロークエリログを表示 | インスタンスに接続せずにスロークエリを特定します |