Azure Database for MySQL - フレキシブル サーバーでの CPU 使用率の高さをトラブルシューティングする
適用対象: Azure Database for MySQL - 単一サーバー Azure Database for MySQL - フレキシブル サーバー
重要
Azure Database for MySQL シングル サーバーは廃止パスにあります。 Azure Database for MySQL フレキシブル サーバーにアップグレードすることを強くお勧めします。 Azure Database for MySQL フレキシブル サーバーへの移行の詳細については、Azure Database for MySQL シングル サーバーの現状に関するページを参照してください
Azure Database for MySQL フレキシブル サーバーには、サーバー上のリソースのボトルネックとパフォーマンスの問題を特定するために使用できるさまざまなメトリックが用意されています。 サーバーで CPU 使用率が高いかどうかを判断するには、"ホスト CPU 使用率"、"合計接続数"、"ホスト メモリの割合"、"IO 割合" などのメトリックを監視します。 これらのメトリックの組み合わせを表示すると、Azure Database for MySQL フレキシブル サーバー上での CPU 使用率の増加の原因に関する分析情報が得られる場合があります。
たとえば、CPU 使用率が上昇する原因となるデータベース クエリの急増の発端となる接続の急増を考えてみましょう。
メトリックのキャプチャに加えて、ワークロードをトレースして、1 つ以上のクエリが CPU 使用率の急増を引き起こしているかどうかを把握することも重要です。
高い CPU 使用率の原因
CPU スパイクは、さまざまな理由で発生する可能性があります。接続の急増、SQL クエリの不適切な記述、またはその両方の組み合わせが主な原因と考えられます。
接続の急増
接続数の増加はスレッドの増加につながる可能性があります。その場合、これらの接続をクエリやリソースと共に管理する必要があるため、CPU 使用率が上昇する可能性があります。 接続の急増のトラブルシューティングを行うには、[合計接続数] メトリックを確認してください。これらの接続の詳細については次のセクションを参照してください。 performance_schema を使用し、以下のコマンドによってサーバーに現在接続されているホストとユーザーを特定できます。
現在接続されているホスト
select HOST,CURRENT_CONNECTIONS From performance_schema.hosts
where CURRENT_CONNECTIONS > 0
and host not in ('NULL','localhost');
現在接続されているユーザー
select USER,CURRENT_CONNECTIONS from performance_schema.users
where CURRENT_CONNECTIONS >0
and USER not in ('NULL','azure_superuser');
SQL クエリの不適切な記述
インデックスのない多数の行の実行とスキャンにリソースを大量に消費するクエリや、一時的な並べ替えを他の非効率的なプランと共に実行するクエリがある場合、CPU スパイクが発生する可能性があります。 クエリによっては単一のセッションではすばやく実行できても、複数のセッションで実行すると CPU スパイクが発生する可能性があります。 そのため、show processlist からキャプチャしたクエリを常に説明すること、それらの実行プランの効率性を保証することが重要です。 これを実現するには、フィルターや where 句を使用して最小限の数の行をスキャンするようにし、インデックスを使用し、さらに大規模な一時的並べ替えと他の不適切な実行プランの併用を回避します。 実行プランの詳細については、「EXPLAIN 出力フォーマット」を参照してください。
現在のワークロードの詳細のキャプチャ
SHOW (FULL) PROCESSLIST コマンドを実行すると、Azure Database for MySQL フレキシブル サーバー インスタンスに現在接続されているすべてのユーザー セッションの一覧が表示されます。 また、各セッションの現在の状態とアクティビティに関する詳細も提供します。
このコマンドは、現在のセッション状態のスナップショットのみを生成し、セッションの履歴アクティビティに関する情報を提供しません。
このコマンドの実行からの出力例を見てみましょう。
mysql> SHOW FULL PROCESSLIST;
+-------+------------------+--------------------+---------------+-------------+--------+-----------------------------+------------------------------------------+
| Id | User | Host | db | Command | Time | State | Info |
+-------+------------------+--------------------+---------------+-------------+--------+-----------------------------+------------------------------------------+
| 1 | event_scheduler | localhost | NULL | Daemon | 13 | Waiting for next activation | NULL |
| 6 | azure_superuser | 127.0.0.1:33571 | NULL | Sleep | 115 | | NULL
|
| 24835 | adminuser | 10.1.1.4:39296 | classicmodels | Query | 7 | Sending data | select * from classicmodels.orderdetails;|
| 24837 | adminuser | 10.1.1.4:38208 | NULL | Query | 0 | starting | SHOW FULL PROCESSLIST |
+-------+------------------+--------------------+---------------+-------------+--------+-----------------------------+------------------------------------------+
5 rows in set (0.00 sec)
顧客所有のユーザー "adminuser" が所有するセッションが 2 つあり、どちらも同じ IP アドレスから取得されていることに注意してください。
- セッション 24835 では、過去 7 秒間、SELECT ステートメントが実行されています。
- セッション 24837 では、"show full processlist" ステートメントが実行されています。
必要に応じて、運用ワークロードの CPU 使用率が急増する原因となったレポートまたは HTAP クエリなどのクエリを終了することが必要になる場合があります。 ただし、CPU 使用率を下げるためにアクションを実行する前に、クエリを終了した場合の潜在的な結果を常に考慮してください。 CPU スパイクにつながる長時間実行されるクエリが特定された場合は、リソースが最適に使用されるようにこれらのクエリを調整します。
詳細な現在のワークロード分析
セッション、トランザクション、クエリの状態に関する正確な情報を取得するには、少なくとも 2 つの情報ソースを使用する必要があります。
- INFORMATION_SCHEMA.PROCESSLIST テーブルのサーバーのプロセス一覧です。SHOW [FULL] PROCESSLIST コマンドを実行してアクセスすることもできます。
- INFORMATION_SCHEMA.INNODB_TRX テーブルからの InnoDB のトランザクション メタデータです。
これらのうち 1 つだけのソースの情報では、接続とトランザクションの状態を説明することはできません。 たとえば、プロセスの一覧では、セッションに関連付けられている開いているトランザクションがあるかどうかは通知されません。 一方、トランザクション メタデータには、セッションの状態とその状態で費やされた時間は表示されません。
次のクエリ例では、プロセス リスト情報と InnoDB トランザクション メタデータの重要な部分の一部を組み合わせます。
mysql> select p.id as session_id, p.user, p.host, p.db, p.command, p.time, p.state, substring(p.info, 1, 50) as info, t.trx_started, unix_timestamp(now()) - unix_timestamp(t.trx_started) as trx_age_seconds, t.trx_rows_modified, t.trx_isolation_level from information_schema.processlist p left join information_schema.innodb_trx t on p.id = t.trx_mysql_thread_id \G
次の例は、このクエリからの出力を示しています。
*************************** 1. row ***************************
session_id: 11
user: adminuser
host: 172.31.19.159:53624
db: NULL
command: Sleep
time: 636
state: cleaned up
info: NULL
trx_started: 2019-08-01 15:25:07
trx_age_seconds: 2908
trx_rows_modified: 17825792
trx_isolation_level: REPEATABLE READ
*************************** 2. row ***************************
session_id: 12
user: adminuser
host: 172.31.19.159:53622
db: NULL
command: Query
time: 15
state: executing
info: select * from classicmodels.orders
trx_started: NULL
trx_age_seconds: NULL
trx_rows_modified: NULL
trx_isolation_level: NULL
セッションごとのこの情報の分析を次の表に示します。
領域 | 分析 |
---|---|
セッション 11 | このセッションは現在アイドル状態 (スリープ状態) であり、クエリは実行されておらず、636 秒間その状態でした。 セッション内で、過去 2908 秒間開かれているトランザクションでは 17,825,792 行が変更され、REPEATABLE READ 分離が使用されています。 |
セッション 12 | セッションは現在、これまで 15 秒間実行されている SELECT ステートメントを実行しています。 trx_started と trx_age_seconds の NULL 値で示されているように、セッション内で実行されているクエリはありません。 セッションでは、より緩やかな READ COMMITTED 分離を使用していない限り、ガベージ コレクションが実行されている限り、その境界を保持し続けます。 |
セッションがアイドル状態として報告された場合、もうステートメントは実行されていないことに注意してください。 この時点で、セッションは以前の作業をすべて完了し、クライアントからの新しいステートメントを待機しています。 ただし、アイドル状態のセッションでは、引き続きいくらかの CPU 消費量とメモリ使用量があります。
開いているトランザクションの一覧表示
次のクエリからの出力には、データベース サーバーに対して現在実行されているすべてのトランザクションの一覧が、トランザクションの開始時刻順に表示されるため、予想される実行時間を超える長期トランザクションやブロックしているトランザクションがあるかどうかを簡単に識別できます。
SELECT trx_id, trx_mysql_thread_id, trx_state, Unix_timestamp() - ( To_seconds(trx_started) - To_seconds('1970-01-01 00:00:00') ) AS trx_age_seconds, trx_weight, trx_query, trx_tables_in_use, trx_tables_locked, trx_lock_structs, trx_rows_locked, trx_rows_modified, trx_isolation_level, trx_unique_checks, trx_is_read_only FROM information_schema.innodb_trx ORDER BY trx_started ASC;
スレッドの状態を理解する
実行中の高い CPU 使用率に寄与するトランザクションは、次のセクションで説明するように、さまざまな状態のスレッドを有している可能性があります。 この情報を使用して、クエリのライフサイクルとさまざまなスレッドの状態について理解を深めてください。
アクセス許可の確認とテーブルを開く
通常、この状態は、開いているテーブル操作に長時間を要していることを意味します。 通常は、テーブル キャッシュ サイズを増やして問題を改善できます。 ただし、テーブルの開きが遅い場合は、同じデータベースの下にテーブルが多すぎるなど、他の問題を示している場合もあります。
データの送信
この状態は、スレッドがネットワーク経由でデータを送信していることを意味しますが、クエリがディスクまたはメモリからデータを読み取っていることを示している場合もあります。 この状態は、シーケンシャル テーブル スキャンによって発生する可能性があります。 ディスクからメモリに大量のページが提供されているかどうかを判断するには、innodb_buffer_pool_reads と innodb_buffer_pool_read_requests の値を確認する必要があります。 詳しくは、「Azure Database for MySQL - フレキシブル サーバーでのメモリ不足に関する問題のトラブルシューティング」をご覧ください。
更新中
通常、この状態は、スレッドで書き込み操作が実行されていることを意味します。 パフォーマンス モニターの IO 関連のメトリックを確認して、現在のセッションの内容について理解を深めましょう。
<lock_type> ロックを待機中
この状態は、スレッドが 2 つ目のロックを待機していることを示します。 ほとんどの場合、メタデータ ロックである可能性があります。 他のすべてのスレッドを確認し、ロックを取得している対象を確認する必要があります。
待機イベントの理解と分析
データベース内で長い待機または多数の待機が発生すると CPU 使用率が増加する可能性があるため、MySQL エンジンの基になる待機イベントを理解することが重要です。 次の例は、適切なコマンドとサンプル出力を示しています。
SELECT event_name AS wait_event,
count_star AS all_occurrences,
Concat(Round(sum_timer_wait / 1000000000000, 2), ' s') AS total_wait_time,
Concat(Round(avg_timer_wait / 1000000000, 2), ' ms') AS
avg_wait_time
FROM performance_schema.events_waits_summary_global_by_event_name
WHERE count_star > 0 AND event_name <> 'idle'
ORDER BY sum_timer_wait DESC LIMIT 10;
+--------------------------------------+-----------------+-----------------+---------------+
| wait_event | all_occurrences | total_wait_time | avg_wait_time |
+--------------------------------------+-----------------+-----------------+---------------+
| wait/io/file/sql/binlog | 7090 | 255.54 s | 36.04 ms |
| wait/io/file/innodb/innodb_log_file | 17798 | 55.43 s | 3.11 ms |
| wait/io/file/innodb/innodb_data_file | 260227 | 39.67 s | 0.15 ms |
| wait/io/table/sql/handler | 5548985 | 11.73 s | 0.00 ms |
| wait/io/file/sql/FRM | 1237 | 7.61 s | 6.15 ms |
| wait/io/file/sql/dbopt | 28 | 1.89 s | 67.38 ms |
| wait/io/file/myisam/kfile | 92 | 0.76 s | 8.30 ms |
| wait/io/file/myisam/dfile | 271 | 0.53 s | 1.95 ms |
| wait/io/file/sql/file_parser | 18 | 0.32 s | 17.75 ms |
| wait/io/file/sql/slow_log | 2 | 0.05 s | 25.79 ms |
+--------------------------------------+-----------------+-----------------+---------------+
10 rows in set (0.00 sec)
SELECT ステートメントの実行時間を制限する
SELECT クエリに関連するデータベース操作の実行コストと実行時間がわからない場合は、実行時間の長い SELECT がデータベース サーバーの予測不可能性またはボラティリティにつながる可能性があります。 ステートメントとトランザクションのサイズ、および関連するリソース使用率は、基になるデータ セットの増加に応じて増加し続けます。 この無制限の増加により、エンド ユーザーのステートメントとトランザクションにますます時間がかかり、データベース サーバーが過負荷になるまでリソースの消費が増加します。 無制限の SELECT クエリを使用する場合は、この期間を超えるクエリが中止されるように、max_execution_time パラメーターを構成することをお勧めします。
Recommendations
- クエリを実行するのに十分なリソースがデータベースに割り当てられていることを確認します。 場合によっては、インスタンス サイズをスケールアップして、ワークロードに合わせて CPU コアをさらに取得する必要が生じることもあります。
- 小さいトランザクションに分割することにより、大規模または実行時間の長いトランザクションを回避します。
- 可能な場合は、読み取りレプリカ サーバーで SELECT ステートメントを実行します。
- システムが指定されたしきい値のいずれかを超えた場合に通知を受け取るように、"ホストの CPU 使用率" アラートを使用します。
- Query Performance Insights または Azure Workbooks を使用して、問題が発生していたり実行に時間がかかったりするクエリを特定し、それらを最適化します。
- 運用データベース サーバーの場合は、診断を定期的に収集して、すべてがスムーズに実行されていることを確認します。 そうでない場合は、特定した問題をトラブルシューティングして解決します。
次の手順
重要度の高い質問に対する回答を見つける、質問を投稿する、または回答するには、Stack Overflow にアクセスしてください。