Amazon DocumentDB
開発者ガイド

パフォーマンスとリソース使用率

このセクションでは、Amazon DocumentDB デプロイにおける一般的な診断の問題に関する質問と解決策を示します。提供されている例では mongo シェルを使用し、個々のインスタンスに範囲を設定しています。インスタンスエンドポイントを見つけるには、「Amazon DocumentDB エンドポイントの管理」を参照してください 。

長時間実行されているクエリやブロックされているクエリを見つけて終了する方法

ユーザークエリの実行は、最適でないクエリプランのために遅くなることも、リソースの競合のためにブロックされる可能性もあります。

クエリプランが最適でないために長時間実行されているクエリ、またはリソースの競合のためにブロックされているクエリを見つけるには、currentOp コマンドを使用します。コマンドをフィルタリングすると、終了する関連クエリのリストを絞り込むことができます。クエリを終了できるようにするには、長時間実行されているクエリに opid を関連付ける必要があります。

次のクエリでは、currentOp コマンドを使用して、ブロックされている、または 10 秒以上実行されているクエリをすべてリストします。

db.adminCommand({ aggregate: 1, pipeline: [ {$currentOp: {}}, {$match: {$or: [ {secs_running: {$gt: 10}}, {WaitState: {$exists: true}}]}}, {$project: {_id:0, opid: 1, secs_running: 1}}], cursor: {} });

次に、クエリを絞り込み、10 秒以上実行されているクエリの opid を見つけて終了できます。

10 秒以上実行されているクエリを見つけ出して終了するには

  1. クエリの opid を見つけます。

    db.adminCommand({ aggregate: 1, pipeline: [ {$currentOp: {}}, {$match: {$or: [{secs_running: {$gt: 10}}, {WaitState: {$exists: true}}]}}], cursor: {} });

    このオペレーションによる出力は、次のようになります (JSON 形式)。

    { "waitedMS" : NumberLong(0), "cursor" : { "firstBatch" : [ { "opid" : 24646, "secs_running" : 12 } ], "id" : NumberLong(0), "ns" : "admin.$cmd" }, "ok" : 1 }
  2. killOp オペレーションを使用してクエリを終了します。

    db.adminCommand({killOp: 1, op: 24646});

クエリプランを参照してクエリを最適化する方法

クエリの実行が遅い場合は、関連するドキュメントを選択するためにクエリの実行でコレクションのフルスキャンが必要である可能性があります。場合によっては、適切なインデックスの作成により、クエリの実行を高速化できます。このシナリオを検出し、インデックスを作成するフィールドを決定するには、explain コマンドを使用します。

次のように、explain コマンドで改善する必要があるクエリを実行します。

db.runCommand({explain: {<query document>}})

以下に示しているのは、オペレーションの例です。

db.runCommand({explain:{ aggregate: "sample-document", pipeline: [{$match: {x: {$eq: 1}}}], cursor: {batchSize: 1}} });

このオペレーションによる出力は、次のようになります (JSON 形式)。

{ "queryPlanner" : { "plannerVersion" : 1, "namespace" : "db.test", "winningPlan" : { "stage" : "COLLSCAN" } }, "serverInfo" : { "host" : "...", "port" : ..., "version" : "..." }, "ok" : 1 }

前述の出力は、$match ステージでコレクション全体をスキャンし、各ドキュメントのフィールド "x" が 1 に等しいかどうか確認する必要があることを示しています。コレクションに多くのドキュメントがある場合、コレクションのスキャン(および全体的なクエリのパフォーマンス)は非常に低速になります。したがって、explain コマンドの出力に "COLLSCAN" が存在することは、適切なインデックスを作成することで、クエリのパフォーマンスを向上できることを示します。

この例では、クエリはすべてのドキュメントでフィールド "x" が 1 と等しいかどうかを確認します。したがって、フィールド "x" でインデックスを作成すると、クエリは完全なコレクションスキャンを回避し、インデックスを使用して関連ドキュメントをより早く返すことができます。

フィールド "x" でインデックスを作成した後、explain 出力は次のようになります。

{ "queryPlanner" : { "plannerVersion" : 1, "namespace" : "db.test", "winningPlan" : { "stage" : "IXSCAN", "indexName" : "x_1", "direction" : "forward" } }, "serverInfo" : { "host" : "...", "port" : ..., "version" : "..." }, "ok" : 1 }

フィールド "x" にインデックスを作成すると、$match ステージはインデックススキャンを使用して、述語 "x = 1" を評価する必要があるドキュメントの数を減らすことができます。

小規模なコレクションで、パフォーマンスの向上がごくわずかである場合、Amazon DocumentDB クエリプロセッサはインデックスを使用しないように選択することがあります。

インスタンスで実行中のすべての操作をリストする方法

ユーザーまたはマスターユーザーは、診断およびトラブルシューティングの目的で、インスタンスで実行されている現在のすべての操作を頻繁にリストします。(ユーザーの管理の詳細については、Amazon DocumentDB ユーザーの管理 を参照してください。)

mongo シェルで、次のクエリを使用して、Amazon DocumentDB インスタンスで実行中のすべてのオペレーションをリストできます。

db.adminCommand({currentOp: 1, $all: 1});

クエリは、インスタンス上で現在動作しているすべてのユーザークエリと内部システムタスクの完全なリストを返します。

このオペレーションによる出力は、次のようになります (JSON 形式)。

{ "inprog" : [ { "desc" : "INTERNAL" }, { "desc" : "TTLMonitor", "active" : false }, { "desc" : "GARBAGE_COLLECTION" }, { "client" : ..., "desc" : "Conn", "active" : true, "killPending" : false, "opid" : 195, "ns" : "admin.$cmd", "command" : { "currentOp" : 1, "$all" : 1 }, "op" : "command", "$db" : "admin", "secs_running" : 0, "microsecs_running" : NumberLong(68), "clientMetaData" : { "application" : { "name" : "MongoDB Shell" }, "driver" : { ... }, "os" : { ... } } }], "ok" : 1 }

次に示すのは、"desc" フィールドの有効な値です。

  • INTERNAL — カーソルのクリーンアップや古いユーザーのクリーンアップタスクなどの内部システムタスク。

  • TTLMonitor — 有効期限 (TTL) モニタリングスレッド。その実行ステータスが "active" フィールドに反映されています。

  • GARBAGE_COLLECTION — 内部ガベージコレクタースレッド。最大 3 つのガベージコレクタースレッドをシステムで同時に実行できます。

  • CONN — ユーザーのクエリ。

前の出力では、システムで実行されているすべてのユーザークエリもリストされます。各ユーザークエリはデータベースとコレクションのコンテキストで実行され、これらの 2 つを統合したものが、名前空間と呼ばれます。各ユーザークエリの名前空間は、"ns" フィールドで利用できます。

特定の名前空間で実行されているすべてのユーザークエリをリストする必要がある場合があります。したがって、前の出力は "ns" フィールドでフィルタリングする必要があります。次にフィルター処理の出力を達成するためのクエリの例を示します。クエリは、データベース "db" とコレクション "test"(つまり、"db.test" 名前空間)で現在実行されているすべてのユーザークエリをリストします。

db.adminCommand({aggregate: 1, pipeline: [{$currentOp: {allUsers: true, idleConnections: true}}, {$match: {ns: {$eq: "db.test"}}}], cursor: {} });

システムのマスターユーザーは、すべてのユーザーのクエリと、すべての内部システムタスクを表示できます。他のすべてのユーザーは、各自のクエリのみを表示できます。

クエリと内部システムタスクの合計数が、デフォルトのバッチカーソルサイズを超えている場合、mongo シェルは残りの結果を表示するイテレーターオブジェクト 'it' を自動的に生成します。すべての結果がなくなるまで、コマンド 'it' の実行を継続します。

クエリが進行するタイミングを知る方法

ユーザーのクエリは、最適とはいえないクエリプランが原因で実行速度が遅くなったり、リソースの競合が原因でブロックされたりすることがあります。このようなクエリのデバッグは複数ステップのプロセスであり、同じステップを複数回実行することが必要になる場合があります。

デバッグの最初のステップでは、長時間実行されているか、ブロックされているすべてのクエリをリストします。次のクエリは、10 秒以上実行されているか、リソースを待機しているすべてのユーザークエリをリストします。

db.adminCommand({aggregate: 1, pipeline: [{$currentOp: {}}, {$match: {$or: [{secs_running: {$gt: 10}}, {WaitState: {$exists: true}}]}}, {$project: {_id:0, opid: 1, secs_running: 1, WaitState: 1, blockedOn: 1, command: 1}}], cursor: {} });

前述のクエリを定期的に繰り返して、クエリのリストが変更されているかどうかを確認し、実行時間が長いクエリまたはブロックされているクエリを識別します。

対象のクエリの出力ドキュメントに WaitState フィールドがある場合、クエリの実行が低速であるかブロックされている理由は、リソースの競合であることを示しています。リソースの競合は、I/O、内部システムタスク、またはその他のユーザークエリが原因である可能性があります。

このオペレーションによる出力は、次のようになります (JSON 形式)。

{ "waitedMS" : NumberLong(0), "cursor" : { "firstBatch" : [ { "opid" : 201, "command" : { "aggregate" : ... }, "secs_running" : 208, "WaitState" : "IO" } ], "id" : NumberLong(0), "ns" : "admin.$cmd" }, "ok" : 1 }

同じインスタンスで同時に実行されているさまざまなコレクションで多くのクエリが実行されているか、クエリを実行中のデータセットのインスタンスサイズが小さすぎると、I/O がボトルネックとなる場合があります。クエリが読み取り専用クエリである場合、各コレクションのクエリを別々のレプリカに分離することで、以前の状況を軽減できます。さまざまなコレクション間で同時更新を行う場合、またはデータセットに対するインスタンスサイズが小さすぎる場合の軽減策は、インスタンスをスケールアップすることです。

リソースの競合の原因が他のユーザークエリである場合、出力ドキュメントの "blockedOn" フィールドに、このクエリに影響しているクエリの "opid" が含まれます。"opid" を使用して、すべてのクエリの "WaitState" および "blockedOn" フィールドのチェーンに従って、チェーンの先頭にあるクエリを調べます。

チェーンの先頭にあるタスクが内部タスクである場合の唯一の緩和策は、クエリを終了し、後で再実行することです。

以下は、検索クエリが別のタスクによって所有されているコレクションロックでブロックされるサンプル出力です。

{ "inprog" : [ { "client" : "...", "desc" : "Conn", "active" : true, "killPending" : false, "opid" : 75, "ns" : "...", "command" : { "find" : "...", "filter" : { } }, "op" : "query", "$db" : "test", "secs_running" : 9, "microsecs_running" : NumberLong(9449440), "threadId" : 24773, "clientMetaData" : { "application" : { "name" : "MongoDB Shell" }, "driver" : { ... }, "os" : { ... } }, "WaitState" : "CollectionLock", "blockedOn" : "INTERNAL" }, { "desc" : "INTERNAL" }, { "client" : "...", ... "command" : { "currentOp" : 1 }, ... } ], "ok" : 1 }

"WaitState" の値が "Latch""SystemLock""BufferLock""BackgroundActivity"、または "Other" の場合、リソース競合の原因は内部システムタスクにあります。この状態が長時間続く場合、唯一の緩和策は、クエリを終了し、後で再実行することです。

システムの実行速度が突然遅くなった理由を判断する方法

以下にシステムの速度が低下する一般的な理由を示します。

  • 同時クエリ間の過剰なリソースの競合

  • 時間の経過とともに増加するアクティブな同時クエリの数

  • "GARBAGE_COLLECTION" などの内部システムタスク

時間の経過とともにシステムの使用状況をモニタリングするには、以下の "currentOp" クエリを定期的に実行し、外部ストアに結果を出力します。クエリは、システムの各名前空間内のクエリとオペレーションの数をカウントします。次に、システムの使用状況の結果を分析し、システムへの負荷を把握して適切なアクションを行うことができます。

db.adminCommand({aggregate: 1, pipeline: [{$currentOp: {allUsers: true, idleConnections: true}}, {$group: {_id: {desc: "$desc", ns: "$ns", WaitState: "$WaitState"}, count: {$sum: 1}}}], cursor: {} });

このクエリは、各名前空間で実行されているすべてのクエリとすべての内部システムタスクの合計を返します。また、名前空間ごとに存在する場合は、待機状態の一意の数を返します。

このオペレーションによる出力は、次のようになります (JSON 形式)。

{ "waitedMS" : NumberLong(0), "cursor" : { "firstBatch" : [ { "_id" : { "desc" : "Conn", "ns" : "db.test", "WaitState" : "CollectionLock" }, "count" : 2 }, { "_id" : { "desc" : "Conn", "ns" : "admin.$cmd" }, "count" : 1 }, { "_id" : { "desc" : "TTLMonitor" }, "count" : 1 } ], "id" : NumberLong(0), "ns" : "admin.$cmd" }, "ok" : 1 }

上記の出力では、コレクションロックでブロックされている名前空間 "db.test" に 2 つのユーザークエリ、名前空間 "admin.$cmd" に 1 つのクエリ、および 1 つの内部 "TTLMonitor" タスクがあります。

出力が、ブロック待機状態の多くのクエリを示す場合は、「長時間実行されているクエリやブロックされているクエリを見つけて終了する方法」を参照してください。

1 つ以上のクラスターインスタンスで CPU 使用率が高くなる原因を特定する方法

以下のセクションは、インスタンスの CPU 使用率が高い原因を特定するのに役立ちます。結果は、ワークロードによって異なります。

インスタンスの CPU 使用率が高い理由に応じて、以下の 1 つ以上の操作を行うと役立ちます。

  • プライマリインスタンスで高い CPU 使用率が示され、レプリカインスタンスではそうではない場合、クライアントの読み込み優先設定(secondaryPreferred など)を使用してレプリカ間で読み込みトラフィックを分散することを検討してください。詳細については、「レプリカセットとして Amazon DocumentDB に接続する」を参照してください。

    レプリカを読み込みに使用すると、プライマリインスタンスでより多くの書き込みトラフィックを処理できるようになり、クラスターのリソースをより有効に活用できます。レプリカからの読み込みには結果整合性があります。

  • CPU 使用率が高いことが書き込みワークロードの結果である場合、クラスターのインスタンスのサイズをより大きいインスタンスタイプに変更すると、ワークロードに対応する CPU コアの数が増えます。詳細については、「インスタンス」および「インスタンスクラスの仕様」を参照してください。

  • すべてのクラスターインスタンスで高い CPU 使用率が示され、ワークロードでレプリカが読み取りに使用されている場合、クラスターにレプリカを追加すると、読み取りトラフィックに使用できるリソースが増えます。詳細については、「Amazon DocumentDB インスタンスへのクラスターの追加」を参照してください。

便利なクエリの概要

以下のクエリは、Amazon DocumentDB のパフォーマンスとリソース使用率をモニタリングするのに役立ちます 。

  • 次のクエリを使用して、すべてのアクティビティをリストします。

    db.adminCommand({currentOp: 1, $all: 1});
  • 次のコードは、実行時間が長いクエリまたはブロックされたすべてのクエリをリストします。

    db.adminCommand({aggregate: 1, pipeline: [{$currentOp: {}}, {$match: {$or: [{secs_running: {$gt: 10}}, {WaitState: {$exists: true}}]}}, {$project: {_id:0, opid: 1, secs_running: 1, WaitState: 1, blockedOn: 1, command: 1}}], cursor: {} });
  • 次のコードは、クエリを終了します。

    db.adminCommand({killOp: 1, op: <opid of running or blocked query>});
  • 次のコードを使用して、システム状態の集約ビューを取得します。

    db.adminCommand({aggregate: 1, pipeline: [{$currentOp: {allUsers: true, idleConnections: true}}, {$group: {_id: {desc: "$desc", ns: "$ns", WaitState: "$WaitState"}, count: {$sum: 1}}}], cursor: {} });