ApsaraDB for MongoDB を使用すると、その CPU 使用率が過度に高くなったり、100%に近くなることさえあります。 CPU 使用率が高くなると、データの読み書き操作が遅くなるだけでなく、通常の業務にも影響します。 本ドキュメントでは、アプリケーション用に ApsaraDB for MongoDB の CPU 高使用率の場合のトラブルシューティング方法について説明します。

ApsaraDB for MongoDB での進行中リクエストの分析

  1. mongo shell を介して ApsaraDB for MongoDB インスタンスに接続します。
  2. db.currentOp() コマンドを実行して、ApsaraDB for MongoDB で進行中の操作をチェックします。

    コマンド出力の例は次の通り:

    {
            "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 ロック関連のフィールド 詳細は、公式 MongoDB ドキュメントをご参照ください。
db.currentOp() コマンドの詳細は、 db.currentOp()をご参照ください。
db.currentOp() コマンドを実行して、進行中の操作を確認し、ApsaraDB for MongoDB が時間のかかるリクエストを処理しているかどうかを分析できます。 たとえば、通常の業務では CPU 使用率が高くないとします。 O&M 管理エンジニアが ApsaraDB for MongoDB にログインしてコレクションスキャンが必要な操作を実行すると、CPU使用率が大幅に増加し、ApsaraDB for MongoDB の応答が遅くなります。 この場合は、実行時間が長い操作に注目する必要があります。
異常なリクエストが見つかった場合は、ID(opid フィールドで指定)を記録し、 db.killOp(opid) コマンドを実行してこのリクエストを終了させることができます。

関連する ApsaraDB for MongoDB インスタンスの CPU 使用率がすぐに増加し、アプリケーションの実行開始後も高いままであるとします。 db.currentOp() コマンドの出力に異常なリクエストが見つからない場合は、ApsaraDB for MongoDB で実行中の低速リクエストを分析できます。

ApsaraDB for MongoDB で実行中の低速リクエストに対する分析

ApsaraDB for MongoDB はデフォルトで低速リクエスト Profiling が有効されています。 100 ミリ秒を超えて実行されているリクエストが自動的に関連データベースの system.profile コレクションに記録されます。

  1. mongo shell を介して ApsaraDB for MongoDB インスタンスに接続します。

    詳細は、mongo shell を介したスタンドアロンインスタンスへの接続mongo shell を介したレプリカセットインスタンスへの接続、またはmongo shell を介したシャードクラスタインスタンスへの接続をご参照ください。

  2. データベースにアクセスするには、use <database> コマンドを実行します。
    use mongodbtest
  3. このデータベースの低速リクエストログを確認するには、次のコマンドを実行します。
    db.system.profile.find().pretty()
  4. 低速リクエストログを分析して、ApsaraDB for MongoDB CPU 高使用率の原因を見つけます。
    以下は低速リクエストログの例です。 このリクエストでは、ApsaraDB for MongoDB はインデックスに基づいてデータをクエリするのではなく、コレクションスキャンを実行し、11,000,000 のドキュメントをスキャンしました。
    {
            "op" : "query",
            "ns" : "123.testCollection",
            "command" : {
                    "find" : "testCollection",
                    "filter" : {
                            "name" : "zhangsan"
                    },
                    "$db" : "123"
            },
            "keysExamined" : 0,
            "docsExamined" : 11000000,
            "cursorExhausted" : true,
            "numYield" : 85977,
            "nreturned" : 0,
            "locks" : {
                    "Global" : {
                            "acquireCount" : {
                                    "r" : NumberLong(85978)
                            }
                    },
                    "Database" : {
                            "acquireCount" : {
                                    "r" : NumberLong(85978)
                            }
                    },
                    "Collection" : {
                            "acquireCount" : {
                                    "r" : NumberLong(85978)
                            }
                    }
            },
            "responseLength" : 232,
            "protocol" : "op_command",
            "millis" : 19428,
            "planSummary" : "COLLSCAN",
            "execStats" : {
                    "stage" : "COLLSCAN",
                    "filter" : {
                            "name" : {
                                    "$eq" : "zhangsan"
                            }
                    },
                    "nReturned" : 0,
                    "executionTimeMillisEstimate" : 18233,
                    "works" : 11000002,
                    "advanced" : 0,
                    "needTime" : 11000001,
                    "needYield" : 0,
                    "saveState" : 85977,
                    "restoreState" : 85977,
                    "isEOF" : 1,
                    "invalidates" : 0,
                    "direction" : "forward",
    ....in"
                    }
            ],
            "user" : "root@admin"
    }

低速リクエストログでは、次の点に注意する必要があります。

  • コレクションスキャン(キーワード:COLLSCAN、docsExamined)
    • COLLSCAN はコレクションスキャンを示します。
      リクエストに対するコレクションスキャン(クエリ、更新、削除など)は、多くの CPU リソースを占有する可能性があります。 低速リクエストログで COLLSCAN キーワードが見つかった場合は、これらの低速リクエストによって CPU リソースが占有されている可能性があります。
      このような低速リクエストが頻繁に送信される場合は、クエリのパフォーマンスを最適化するためにクエリされたフィールドにインデックスを作成することをお勧めします。
    • docsExamined フィールドは、ApsaraDB for MongoDB がリクエストをスキャンしたドキュメントの数を示します。 このフィールドの値が大きいほど、このリクエストによって占有される CPU オーバーヘッドが大きいことを示します。
  • 不適切なインデックス(キーワード:IXSCAN、keysExamined)

    keysExamined フィールドは、ApsaraDB for MongoDB がインデックスを使用するリクエストについてスキャンしたインデックスキーの数を示します。 このフィールドの値が大きいほど、このリクエストによって占有される CPU オーバーヘッドが大きいことを示します。

    不適切な、または大量のデータと一致するインデックスを作成しても、CPU のオーバーヘッドを減らしたり、リクエストの実行時間を短縮したりすることはできません。

    たとえば、コレクション内のデータの場合、x フィールドは 1 または 2 にのみ設定され、y フィールドはより広い値範囲に設定されているとします。

    { x: 1, y: 1 }
    { x: 1, y: 2 }
    { x: 1, y: 3 }
    ......
    { x: 1, y: 100000} 
    { x: 2, y: 1 }
    { x: 2, y: 2 }
    { x: 2, y: 3 }
    ......
    { x: 1, y: 100000}

    データ { x: 1, y: 2 } をクエリするために、インデックスを作成することができます。 次の例は 4 つのインデックスを示しています。

    db.createIndex( { x: 1 } ) // This index is inappropriate because a large amount of data has the same value of the x field.
    db.createIndex( { x: 1, y: 1 } ) // This index is inappropriate because a large amount of data has the same value of the x field.
    db.createIndex( { y: 1 } ) // This index is appropriate because a small amount of data has the same value of the y field.
    db.createIndex( { y: 1, x: 1 } ) // This index is appropriate because a small amount of data has the same value of the y field.

    インデックス {y:1} と {y:1、x:1} の違いについては、複合インデックスをご参照ください。

  • 大量データのソート(キーワード:SORT、hasSortStage)
    クエリリクエストにはソートが含まれる場合、hasSortStage フィールドの値は system.profile コレクション内で true になります。 この場合、ApsaraDB for MongoDB はクエリ結果をソートする必要があります。 ソート操作は大量の CPU リソースを消費することを考慮して、ソートのパフォーマンスを最適化するために頻繁にソートされるフィールドにインデックスを作成できます。
    system.profile コレクションに SORT キーワードがある場合は、インデックスを使用してソートパフォーマンスを最適化することを考慮できます。

インデックスの作成や集計などの他の操作(トラバース、クエリ、更新、並べ替え、その他の操作の組み合わせ)も、かなりの CPU リソースを消費する可能性があります。 上記のトラブルシューティング方法を使用することもできます。 Profiling の詳細は、 Database Profiler をご参照ください。

サービス能力の評価

ApsaraDB for MongoDB で進行中のリクエストと低速リクエストを分析して最適化した後は、すべてのリクエストで効率的にインデックスが使用され、ApsaraDB for MongoDB のクエリパフォーマンスが最適化されます。

業務処理中に CPU リソースがまた完全に使用されてしまっている場合は、インスタンスのサービス機能が上限に達している可能性があります。 この場合、インスタンスのリソース使用量を分析するためにモニタリング情報を表示する必要があります。 また、ApsaraDB for MongoDB をテストして、現行インスタンスがビジネスシナリオのデバイスパフォーマンスとサービス機能の要件を満たしているかどうかを確認することもできます。

インスタンスをアップグレードする必要がある場合は、構成の変更の手順に従うことができます。