max_connections の制限に達していないにもかかわらず、Amazon Relational Database Service (Amazon RDS) for PostgreSQL に接続すると、「FATAL: remaining connection slots are reserved for non replicate superuser connections」(FATAL: 残りの接続スロットは非レプリケートスーパーユーザーの接続用に予約されています) というエラーが表示されます。
簡単な説明
Amazon RDS for PostgreSQL では、非スーパーユーザーが使用できる実際の最大接続数は次のように計算されます:
max_connections - superuser_reserved_connections - rds.rds_superuser_reserved_connections。
superuser_reserved_connections のデフォルト値は 3 で、rds.rds_superuser_reserved_connections のデフォルト値は 2 です。
例えば、max_connections の値を 100 に設定すると、非スーパーユーザーが使用できる実際の接続数は次のように計算されます:
100 - 3 - 2 = 95。
Amazon CloudWatch メトリクス DatabaseConnections は、オペレーティングシステムレベルでのデータベースインスタンスへのクライアントネットワーク接続の数を示します。このメトリクスは、ポート 5432 上のインスタンスへの TCP 接続の実際の数を測定することによって計算されます。データベースセッションの数は、このメトリクス値よりも多くなる可能性があります。これは、メトリクスの値に次の値が含まれていないためです。
- ネットワーク接続はもうないが、データベースによってクリーンアップされていないバックエンドプロセス。(例:ネットワークの問題により接続が終了したが、データベースは出力をクライアントに返そうとするまで認識しません。)
- データベースエンジンのジョブスケジューラによって作成されたバックエンドプロセス。(例:pg_cron)
- Amazon RDS 接続
このエラーが表示されるのは、RDS for PostgreSQL インスタンスに接続するアプリケーションが突然接続を作成および切断するためです。これにより、バックエンド接続がしばらく開いたままになる可能性があります。この状態により、pg_stat_activity ビューの値と CloudWatch メトリクス DatabaseConnections の間に不一致が生じる可能性があります。
解決方法
エラーをトラブルシューティングする
このエラーをトラブルシューティングするには、次のチェックを実行します。
- CloudWatch メトリクスの DatabaseConnections を確認します。
- Performance Insights を使用して、numbackends カウンターメトリクスを表示します。この値は、エラーが発生した時点での接続数に関する情報を提供します。Performance Insights を有効にしていない場合は、プライマリユーザーとしてインスタンスにログインします。次に、次のクエリを実行してバックエンドの数を表示します。
SELECT count(*) FROM pg_stat_activity;
終了可能なアイドル接続が見つかった場合は、pg_terminate_backend() 関数を使用してこれらのバックエンドを終了できます。次のクエリを実行すると、終了するアイドル接続をすべて表示できます。このクエリは、15 分を超える時間にわたって、[idle] (アイドル状態)、[idle in transaction] (トランザクションでアイドル状態)、[idle in transaction (aborted)] (トランザクションでアイドル状態 (中断))、および [disabled] (無効) のいずれかの状態のバックエンドプロセスに関する情報を表示します。
SELECT * FROM pg_stat_activity
WHERE pid <> pg_backend_pid()
AND state in ('idle', 'idle in transaction', 'idle in transaction (aborted)', 'disabled')
AND state_change < current_timestamp - INTERVAL '15' MINUTE;
注意: 必ずユースケースに従ってクエリを更新してください。
終了する必要があるすべてのバックエンドプロセスを特定したら、次のクエリを実行してこれらのプロセスを終了します。
注意: この例のクエリは、15 分を超える時間にわたって前述のいずれかの状態にあるすべてのバックエンドプロセスを終了します。
SELECT pg_terminate_backend(pid) FROM pg_stat_activity
WHERE pid <> pg_backend_pid()
AND state in ('idle', 'idle in transaction', 'idle in transaction (aborted)', 'disabled')
AND state_change < current_timestamp - INTERVAL '15' MINUTE
AND usename != 'rdsadmin';
アイドル状態のバックエンドプロセスをすべて終了するには、次のクエリを実行します。
SELECT pg_terminate_backend(pid) FROM pg_stat_activity
WHERE pid <> pg_backend_pid()
AND state in ('idle', 'idle in transaction', 'idle in transaction (aborted)', 'disabled')
AND usename != 'rdsadmin';
注: rdsadmin で作成されたバックエンドプロセスは終了できません。そのため、それらを終了から除外する必要があります。
重要: rds_superuser 権限で RDS for PostgreSQL インスタンスに接続できない場合は、アプリケーションを正常に閉じて一部の接続を解放することを検討してください。
データベース接続の数を管理する
接続プールを使用する
ほとんどの場合、RDS Proxy やサードパーティーの接続プーラーなどの接続プーラーを使用して、特定の時点で開いている接続の数を管理できます。例えば、RDS for PostgreSQL インスタンスの max_connections 値を 500 に設定した場合、最大 400 個の接続用に設定された接続プーラーを使用することで、max_connection に関連するエラーを防ぐことができます。
max_connections 値を引き上げる
ユースケースによっては、max_connections の値を増やすことを検討してください。ただし、max_connections に非常に高い値を設定すると、データベースインスタンスのワークロードとインスタンスクラスに基づいてメモリの問題が発生する可能性があります。
注: max_connections の値を引き上げた場合、その変更を有効にするためにインスタンスを再起動する必要があります。
アイドル状態の接続を終了する
idle_in_transaction_session_timeout パラメータを、ユースケースに適した値に設定できます。このパラメータで指定された時間よりも長く開いているトランザクション内でアイドル状態になっているセッションは終了します。例えば、このパラメータを 10 分に設定すると、10 分を超える時間にわたってトランザクションでアイドル状態になっているクエリは終了します。このパラメータは、この特定の状態でスタックしている接続を管理するのに役立ちます。
PostgreSQL バージョン 14 以降では、idle_session_timeout パラメータを使用できます。このパラメータを設定すると、指定された時間を超えてアイドル状態になっているが、開いているトランザクション内ではないセッションが終了します。
PostgreSQL バージョン 14 以降では、client_connection_check_interval パラメータを使用できます。このパラメータを使用すると、クエリを実行する際のクライアント接続をオプションでチェックする間隔を設定できます。このチェックは、ソケットをポーリングすることによって実行されます。このチェックにより、接続が閉じられたことをカーネルが報告した場合に、長時間実行されているクエリをより早く終了することができます。このパラメータは、バックエンドプロセスとの接続が失われたことを PostgreSQL が認識しない場合に役立ちます。
rds.rds_superuser_reserved_connections 値を引き上げる
rds.rds_superuser_reserved_connections パラメータの値を引き上げることを検討できます。このパラメータのデフォルト値は 2 に設定されています。このパラメータの値を引き上げると、rds_superuser ロールがアタッチされているユーザーからの接続がより多く許可されます。このロールを使用すると、ユーザーは pg_terminate_backend() コマンドを使用してアイドル状態の接続を終了するなどの管理タスクを実行できます。