Amazon RDS または Amazon Aurora PostgreSQL の高い CPU 使用率をトラブルシューティングするにはどうすればよいですか?

最終更新日: 2022 年 6 月 9 日

Amazon Relational Database Service (Amazon RDS) または Amazon Aurora PostgreSQL 互換エディションで、CPU の使用が高くなる原因を特定して解決したいと考えています。

簡単な説明

CPU 使用率が高い場合は、次のツールを組み合わせて原因を特定できます。

解決方法

Amazon CloudWatch メトリクス

CloudWatch メトリクスを使用して、長期間にわたる CPU パターンを識別できます。WriteIOPsReadIOPsReadThroughput、および WriteThroughput のグラフを CPU 使用率と比較して、ワークロードによって高い CPU が発生した時間を調べます。

時間枠が特定されたら、DB インスタンスに関連付けられている拡張モニタリングを確認できます。1、5、10、15、30、または 60 秒の間隔でデータを収集するように拡張モニタリングを設定できます。これにより、CloudWatch よりも詳細なレベルでデータを収集できます。

拡張モニタリング

拡張モニタリングでは、オペレーティングシステム (OS) レベルのビューが提供されます。このビューは、CPU 負荷が高くなっている原因を詳細に確認するのに役立ちます。例えば、負荷平均、CPU 配分 (system% または nice%)、OS プロセスリストを確認できます。

拡張モニタリングを使用すると、1、5、および 15 分間隔で loadAverageMinute データを確認できます。負荷平均が vCPU の数よりも大きい場合は、インスタンスに高い負荷がかかっていることを示します。また、負荷平均が DB インスタンスクラスの vCPU 数より少ない場合、CPU スロットリングがアプリケーションのレイテンシーの原因ではない可能性があります。CPU 使用率の原因を診断する際に誤検出を避けるためにも、平均負荷を確認してください。

例えば、CPU 制限に達する 3,000 個のプロビジョンド IOPS を持つ db.m5.2xlarge インスタンスクラスを使用している DB インスタンスがある場合、次のメトリクス例を確認して、CPU 使用率が高い根本原因を特定できます。次の例では、インスタンスクラスには 8 個の vCPU が関連付けられています。同じ平均負荷で 170 を超えるということは、測定された時間枠の間にマシンが重い負荷を受けていることを示します。

平均負荷時間 (分)

15 170.25
5 391.31
1 596.74

CPU 使用率

ユーザー (%) 0.71
システム (%) 4.9
Nice (%) 93.92
合計 (%) 99.97

注: Amazon RDS では、DB インスタンスで実行されている他のタスクよりもワークロードの優先度が高くなります。これらのタスクに優先順位を付けるため、ワークロードタスクにはより高い Nice 値が与えられます。この結果、拡張モニタリングでは Nice% はデータベースに対してワークロードが使用している CPU の量を表します。

拡張モニタリングを有効にした後、DB インスタンスに関連付けられている OS プロセスリストも確認できます。拡張モニタリングでは、最大 100 個のプロセスが表示されます。これにより、CPU とメモリの使用量に基づいてパフォーマンスに最大の影響を与えるプロセスを特定できます。

拡張モニタリングの結果を pg_stat_activity の結果と組み合わせると、クエリのリソース使用状況を特定しやすくなります。

Performance Insights

Amazon RDS Performance Insights を使用して、特定の時間枠に対応する SQL タブを確認した後、データベースの負荷を担当するクエリを特定できます。

ネイティブ PostgreSQL のビューとカタログ

データベースエンジンレベルで問題が発生した場合、リアルタイムで pg_stat_activity または pg_stat_statements を使用することができます。これは、最も多くトラフィックを送信するマシン、クライアント、IP アドレスをグループ化するのに役立ちます。このデータを使用して、時間の経過に伴う増加、アプリケーションサーバーの増加、またはアプリケーションサーバーがセッションやロックの問題を解決できるかどうかを確認することもできます。詳細については、PostgreSQL のドキュメント 「pg_stat_activity」および「pg_stat_statements」をご参照ください。

pg_stat_statements を有効にするには、既存のカスタムパラメータグループを修正して次の値を設定します。

  • pg_stat_statements to shared_preload_libraries を追加する
  • track_activity_query_size = 4096
  • pg_stat_statements.track = ALL
  • pg_stat_statements.max = 10000

[Apply Immediately] を選択して、DB インスタンスを再起動してください。その後、モニタリングするデータベースで次のようなコマンドを実行します。

注: 次の例では、「デモ」データベースに拡張機能をインストールします。

demo=> select current_database();
current_database
------------------
demo
(1 row)
     
demo=> CREATE EXTENSION IF NOT EXISTS pg_stat_statements;

pg_stat_statements がセットアップされた後、次の方法のうちの 1 つを使用することによって出力をモニタリングすることができます。

    total_time でクエリを一覧表示し、PostgreSQL バージョン 12 以前のデータベースで最も多くの時間を費やしているクエリを確認します。

      SELECT total_time, query
      FROM pg_stat_statements
      ORDER BY total_time DESC LIMIT 10;

        PostgreSQL バージョン 13 以降の場合:

        SELECT total_plan_time+total_exec_time as total_time, query
        FROM pg_stat_statements
        ORDER BY 1 DESC LIMIT 10;

        バッファキャッシュヒット率が低いクエリを一覧表示し、PostgreSQL バージョン 12 以前で次のクエリを実行します。

          SELECT query, calls, total_time, rows, 100.0 * shared_blks_hit / nullif(shared_blks_hit + shared_blks_read, 0) AS hit_percent
          FROM 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_percent
            FROM pg_stat_statements ORDER BY 3 DESC LIMIT 10;

            実行ごとにクエリを一覧表示し、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_written
              FROM 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 使用率が高い場合は、データベースでアイドル接続がないか必ず確認してください。詳細については、「Performance impact of idle PostgreSQL connections」(アイドル状態の PostgreSQL 接続のパフォーマンスへの影響) を参照してください。拡張モニタリングを使用して OS プロセスリストを確認することで、アイドル状態の接続がないかを確認できます。ただし、このリストに表示されるプロセスは最大 100 個です。

              アイドル接続がないかを確認するには、データベースレベルでいくつかのクエリを実行します。

              次のクエリを実行して、アイドル状態のアクティブな現在のセッションを表示します。

              SELECT pid, datname, state, current_timestamp-least(query_start,xact_start) age, application_name, usename, query
              FROM pg_stat_activity
              WHERE 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 を使用することもできます。Amazon RDS Proxy は、数回のクリックで接続プールを設定できるマネージドサービスです。

              Analyze コマンド

              Analyze コマンドは、データベース内のテーブルの内容に関する統計を収集し、その結果を pg_statistic システムカタログに保存します。その後、クエリプランナーは、クエリの最も効率的な実行プランを決定するのに役立てるために、これらの統計を使用します。データベース内のテーブルで Analyze を頻繁に実行しない場合、クエリがより多くのコンピューティングリソースを消費する可能性があります。これは、アクセスするリレーションについての古い統計がシステムに存在するためです。これらの問題は、次の状況で発生します。

              • autovacuum が頻繁に実行されていない。
              • メジャーバージョンのアップグレード後に Analyze が実行されなかった。

              autovacuum が実行されていない: autovacuum は VACUUM コマンドと ANALYZE コマンドの実行を自動化するデーモンです。autovacuum は、データベース内の肥大化したテーブルをチェックし、再利用のために領域を解放します。autovacuum デーモンは、設定されたタプルのしきい値が停止するたびに Analyze オペレーションを実行して、テーブル統計が定期的に更新されるようにします。これにより、クエリプランナーは最新の統計に基づいて最も効率的なクエリプランを使用できます。autovacuum が実行されていない場合、クエリプランナーが次善のクエリプランを作成する場合があります。これにより、クエリによるリソース消費量が増加することがあります。autovacuum のチューニングの詳細については、「Understanding autovacuum in Amazon RDS for PostgreSQL environments」(Amazon RDS for PostgreSQL 環境向けの autovacuum について) および「A case study of tuning autovacuum in Amazon RDS for PostgreSQL」(Amazon RDS for PostgreSQL での autovacuum のチューニングのケーススタディ) を参照してください。

              次のクエリを実行して、autovacuum と autoanalyze がテーブルで最後に実行された日時に関する情報を取得します。

              SELECT relname, last_autovacuum, last_autoanalyze FROM pg_stat_user_tables;

              メジャーバージョンのアップグレード後に Analyze が実行されなかった: PostgreSQL データベースでは、通常、エンジンのメジャーバージョンのアップグレード後にパフォーマンスの問題が発生します。これらの問題の一般的な理由は、アップグレード後に pg_statistic テーブルを更新するために Analyze オペレーションが実行されないことです。RDS for PostgreSQL DB インスタンスのすべてのデータベースについて Analyze オペレーションを必ず実行してください。オプティマイザーの統計は、メジャーバージョンのアップグレード中には転送されません。したがって、リソース使用率の上昇によるパフォーマンスの問題を回避するために、すべての統計を再生成する必要があります。

              メジャーバージョンのアップグレード後に現在のデータベースのすべての通常テーブルの統計を生成するには、パラメータなしで次のコマンドを実行します。

              ANALYZE VERBOSE

              PostgreSQL のログ記録パラメータ

              Amazon RDS for PostgreSQL を使用してクエリログを有効化します。その後、PostgreSQL のエラーログを確認し、log_min_duration_statement および log_statement パラメータが適切な値に設定されていることを確認します。詳細については、PostgreSQL のエラー報告とログ記録に関するドキュメントを参照してください。

              CPU 使用率を下げる

              高 CPU の原因となっているクエリを特定したら、次の方法を使用して CPU 使用率をさらに下げることができます。

              1. チューニングの機会を確認するには、EXPLAINEXPLAIN ANALYZE を使用して注意事項を特定します。詳細については、EXPLAIN に関する PostgreSQL のドキュメントを参照してください。
              2. 繰り返し実行されているクエリがある場合は、準備済みステートメントを使用して CPU への負担を軽減することを検討してください。プリペアドステートメントを繰り返し実行すると、クエリプランがキャッシュされます。したがって、プランは既にキャッシュに存在するため、さらなる実行のためのプランニングの時間はさらに短くなります。

              この記事はお役に立ちましたか?


              請求に関するサポートまたは技術サポートが必要ですか?