Amazon RDS または Amazon Aurora PostgreSQL で CPU 使用率が高い場合のトラブルシューティング方法を教えてください。
Amazon Relational Database Service (Amazon RDS) または Amazon Aurora PostgreSQL 互換エディションのインスタンスで CPU 使用率が増加する原因を特定し、解決したいです。
簡単な説明
CPU 使用率が高くなる原因を特定するには、次のツールを使用します。
- Amazon CloudWatch メトリクス
- 拡張モニタリングのメトリクス
- Performance Insights メトリクス
- PostgreSQL のネイティブビューとカタログ (pg_stat_statements、pg_stat_activity、および pg_stat_user_tables など)
- データベース内のアイドル接続
- PostgreSQL のウェブサイトで入手できる ANALYZE コマンド
- 長時間実行されるクエリ、autovacuum、ロック待機、および接続と切断のリクエストをログ記録するための PostgreSQL の記録パラメータ
解決策
CloudWatch メトリクスをレビューする
CloudWatch メトリクスを使用すると、長期間にわたり CPU パターンを識別できます。WriteIOPs、ReadIOPs、ReadThroughput、および WriteThroughput のグラフを CPU 使用率と比較して、ワークロードによって CPU 使用率が増加した期間を特定します。
期間を特定した後、DB インスタンスに関連付けられてた拡張モニタリングのデータを確認します。拡張モニタリングの収集間隔を 1 秒、5 秒、10 秒、15 秒、30 秒、または 60 秒に設定すると、より詳細なレベルでデータを収集できます。
拡張モニタリングを使用する
拡張モニタリングでは、オペレーティングシステム (OS) レベルのビューを取得できます。例えば、ワークロードの平均、CPU 配分 (System% または Nice%)、OS プロセスリストをレビューします。詳しくは、「OS の監視」を参照してください。
loadAverageMinute データは、1 分、5 分、15 分間隔で確認できます。負荷平均が vCPU の数よりも大きい場合、インスタンスに大きな負荷がかかっています。負荷平均が DB インスタンスクラスの vCPU の数より小さい場合、CPU のスロットリングはアプリケーション遅延の原因ではない可能性があります。CPU 使用率が増加する原因をトラブルシューティングする際は、負荷平均をチェックし、誤検出を避けてください。
たとえば、プロビジョンド IOPS が 3000 の db.m5.2xlarge インスタンスクラスを使用する DB インスタンスがあり、CPU 制限に達しており、8 つの vCPU がそのインスタンスクラスに関連付けられている場合、同じ負荷平均が 170 を超える場合は、測定した期間中にマシンに大きな負荷がかかっています。
負荷平均 (分)
- 15: 170.25
- 5: 391.31
- 1: 596.74
CPU 使用率
- User (%): 0.71
- System (%): 4.9
- Nice (%): 93.92
- Total (%): 99.97
注: 拡張モニタリングの Nice% は、データベースに対してワークロードが使用している CPU の量を表します。
拡張モニタリングを有効にした後は、DB インスタンスに関連付けられている OS プロセスリストも確認できます。拡張モニタリングでは、パフォーマンスに影響しているプロセスを最大 100 件特定できます。拡張モニタリングの結果を pg_stat_activity の結果と組み合わせると、クエリのリソース使用状況を特定しやすくなります。
Performance Insights を使用する
Amazon RDS Performance Insights を使用すると、データベース負荷の原因となっているクエリを特定できます、。特定の期間に対応する SQL タブを確認します。
ネイティブ PostgreSQL ビューとカタログを確認する
データベースエンジンレベルでは、pg_stat_activity および pg_stat_statements を使用できます。問題がリアルタイムで発生する場合は、pg_stat_activity または pg_stat_statements を使用して、最も多くのトラフィックを送信するマシン、クライアント、IP アドレスをグループ化します。
このデータを使用すると、時間の経過に伴う増加やアプリケーションサーバーでの増加を確認できます。アプリケーションサーバーにおいて、セッションの滞留やロックの問題が発生していないかどうかも確認できます。詳細については、PostgreSQL のウェブサイトで pg_stat_activity と pg_stat_statements を参照してください。
pg_stat_statements を有効にするには、次の手順を実行します。
-
pg_stat_statements を shared_preload_libraries に追加します。
-
track_activity_query_size を 4096 に設定します。
-
pg_stat_statements.track を ALL に設定します。
-
pg_stat_statements.max を 10000 に設定します。
-
[すぐに適用] を選択し、DB インスタンスを再起動します。
-
監視するデータベースで、次のコマンドを実行します。
demo=> select current_database();current_database------------------ demo (1 row) demo=> CREATE EXTENSION IF NOT EXISTS pg_stat_statements;注: 上記のコマンドを実行すると、demo データベースに拡張機能がインストールされます。
pg_stat_statements を設定した後、次のいずれかの方法で出力を監視します。データベース内で最も時間のかかるクエリ、バッファキャッシュのヒット率が低いクエリ、実行ごとのクエリを確認できます。
データベース内で最も時間がかかっているクエリを確認するには、PostgreSQL のバージョンに応じて次のクエリを実行します。
PostgreSQL バージョン 12 以前:
SELECT total_time, queryFROM pg_stat_statements ORDER BY total_time DESC LIMIT 10;
PostgreSQL バージョン 13 以降:
SELECT total_plan_time+total_exec_time as total_time, queryFROM pg_stat_statements ORDER BY 1 DESC LIMIT 10;
バッファキャッシュのヒット率が低いクエリを一覧表示するには、PostgreSQL のバージョンに応じて次のクエリを実行します。
PostgreSQL バージョン 12 以前:
SELECT query, calls, total_time, rows, 100.0 * shared_blks_hit / nullif(shared_blks_hit + shared_blks_read, 0) AS hit_percentFROM pg_stat_statements ORDER BY total_time DESC LIMIT 10;
PostgreSQL バージョン 13 以降:
SELECT query, calls, total_plan_time+total_exec_time as total_time, rows, 100.0 * shared_blks_hit / nullif(shared_blks_hit +shared_blks_read, 0) AS hit_percentFROM pg_stat_statements ORDER BY 3 DESC LIMIT 10;
実行ごとにクエリを一覧表示し、経時的にクエリをサンプリングするには、PostgreSQL のバージョンに応じて次のクエリを実行します。
PostgreSQL バージョン 12 以前:
SELECT query, calls, total_time/calls as avg_time_ms, rows/calls as avg_rows,temp_blks_read/calls as avg_tmp_read, temp_blks_written/calls as avg_temp_writtenFROM pg_stat_statements WHERE calls != 0 ORDER BY total_time DESC LIMIT 10;
PostgreSQL バージョン 13 以降:
SELECT query,calls, (total_plan_time+total_exec_time as total_time)/calls as avg_time_ms, rows/calls as avg_rows, temp_blks_read/calls as avg_tmp_read, temp_blks_written/calls as avg_temp_written FROM pg_stat_statements WHERE calls != 0 ORDER BY 3 DESC LIMIT 10;
データベース内でアイドル接続が起こっていないか確認する
データベース内でアイドル接続が発生すると、メモリや CPU などのコンピューティングリソースを消費する可能性があります。インスタンスの CPU 使用率が高い場合は、データベースでアイドル接続がないか確認してください。詳細については、「PostgreSQL のアイドル接続によるパフォーマンスへの影響」を参照してください。
拡張モニタリングを使用すると、OS プロセスリストを参照し、アイドル接続がないかを確認できます。ただし、リストには最大 100 プロセスのみが表示されます。データベースレベルでのアイドル接続がないか確認するには、次のクエリを実行します。
アイドル状態およびアクティブ状態の現在のセッションを確認します。
SELECT pid, datname, state, current_timestamp-least(query_start,xact_start) age, application_name, usename, queryFROM pg_stat_activityWHERE query != '<IDLE> 'AND query NOT ILIKE '%pg_stat_activity%' AND usename!='rdsadmin' ORDER BY query_start desc; SELECT application_name,pid,wait_event_type,wait_event,current_timestamp-least(query_start,xact_start) AS runtime, query AS current_query FROM pg_stat_activity WHERE not pid=pg_backend_pid() AND query NOT ILIKE '%pg_stat_activity%' AND usename!='rdsadmin';
各ユーザーとアプリケーション名での接続数を取得します。
postgres=> SELECT application_name,count(*) FROM pg_stat_activity GROUP BY application_name; application_name | count ------------------------+------- psql | 1 PostgreSQL JDBC Driver | 1 | 5 (3 rows) postgres=> SELECT usename,count(*) FROM pg_stat_activity GROUP BY usename; usename | count ----------+------- master | 4 user1 | 1 rdsadmin | 2 (3 rows)
アイドル状態の接続を特定した後、次のクエリのいずれかを実行して接続を終了します。
psql=> SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE usename = 'example-username' AND pid <> pg_backend_pid() AND state in ('idle');
または、
SELECT pg_terminate_backend (example-pid);
アプリケーションで発生する接続数が多すぎる場合は、そのアプリケーションで変更を行い、メモリと CPU リソースがそれらの接続を管理しないようにします。そのためには、接続数を制限するか、PgBouncer などの接続プーラーを使用します。Amazon RDS Proxy を使用して接続プールを設定することもできます。
ANALYZE コマンドを実行する
ANALYZE コマンドは、データベース内のテーブルの内容に関する統計情報を収集し、その結果を pg_statistic システムカタログに保存します。その後、クエリプランナーがそれらの統計情報を使用してクエリに最も効率的な実行プランを判断します。データベース内のテーブルで ANALYZE を頻繁に実行しない場合、システム内の統計情報が古くなるため、クエリが使用するコンピューティングリソースが増加することがあります。
次の要因で、統計情報が古くなります。
- autovacuum を頻繁に実行していない場合。
- メジャーバージョンのアップグレード後に ANALYZE 操作を実行しなかった場合。
autovacuum は、データベース内の肥大化したテーブルをチェックし、再利用のために領域を解放します。autovacuum デーモンは、設定されたタプルのしきい値が無効になったときに ANALYZE コマンドを実行し、テーブルの統計情報が定期的に更新されるようにします。
詳細については、次のリソースを参照してください。
- Understanding autovacuum in Amazon RDS for PostgreSQL environments
- Amazon RDS for PostgreSQL における autovacuum 調整のケーススタディ
autovacuum と autoanalyze が最後にテーブルで実行された時間を特定するには、次のクエリを実行します。
SELECT relname, last_autovacuum, last_autoanalyze FROM pg_stat_user_tables;
ANALYZE コマンドを実行して pg_statistic テーブルを更新し、エンジンのメジャーバージョンアップグレード後にパフォーマンスの問題が起こらないようにしてください。RDS for PostgreSQL DB インスタンスのすべてのデータベースで ANALYZE 操作を実行します。
リソース使用率の上昇によるパフォーマンスの問題を回避するために、すべての統計情報を再生成します。メジャーバージョンのアップグレード後に現在のデータベースのすべての通常テーブルに関する統計情報を生成するには、パラメータを指定せずに次のコマンドを実行します。
ANALYZE VERBOSE
PostgreSQL エラーログを確認する
Amazon RDS を使用して PostgreSQL のクエリログを有効にする次に、PostgreSQL エラーログを参照し、log_min_duration_statement および log_statement パラメータが適切な値に設定されていることを確認します。詳細については、PostgreSQL のウェブサイトで「エラーのレポートと記録」を参照してください。
CPU 使用率を削減する
CPU 使用率が増加する原因となっているクエリを特定した後は、次の方法で CPU 使用率をさらに削減できます。
- EXPLAIN と EXPLAIN ANALYZE を使用して、クエリプランを調整する方法を特定します。詳細については、PostgreSQL のウェブサイトで 「EXPLAIN の使用」を参照してください。
- 繰り返し実行されるクエリがある場合は、プリペアドステートメントを使用して CPU への負担を軽減します。プリペアドステートメントが繰り返し実行されると、クエリプランがキャッシュされます。プランがキャッシュ済みであり、今後の実行に備えていると、クエリを計画する時間が削減されます。

