冒頭まとめ
PostgreSQLへの接続時に次のエラーが出る場合、利用できる接続枠がすべて使われています。
FATAL: sorry, too many clients already
まず、接続済みの管理用セッションがあればpg_stat_activityで内訳を確認します。不要な接続を安全に終了し、アプリケーションが接続を閉じているか、複数の接続プールの上限が大きすぎないかを調べてください。
max_connectionsを上げるだけでは、接続の増え続ける原因は解消しません。この設定の変更にはPostgreSQLの再起動が必要で、値を増やすと共有メモリを含む資源の割り当ても増えます。先に接続の使い方を直し、それでも必要な場合に限って上限を見直します。
sorry, too many clients alreadyの意味
PostgreSQLは、同時に受け付ける接続数をmax_connectionsで制限しています。利用可能な接続枠を使い切ると、新しい接続を受け付けられず、sorry, too many clients alreadyを返します。
このエラーのSQLSTATEは53300、条件名はtoo_many_connectionsです。アプリケーションでエラーを判定するときは、表示文ではなくSQLSTATEを使うと、言語設定や文言の違いに影響されにくくなります。PostgreSQL公式のエラーコード一覧でも確認できます。
PostgreSQL本体では、接続処理に必要な領域を確保できなかったときに、このエラーを返します。処理はPostgreSQL本体のproc.cで確認できます。
似た2つのエラーとの違い
接続枠が少なくなった段階では、別の文言が表示されることがあります。
FATAL: remaining connection slots are reserved for roles with the SUPERUSER attribute
この場合は接続枠が完全になくなったわけではなく、残りがスーパーユーザー用に確保されています。スーパーユーザーで管理用接続を確立し、接続状況を調査できる可能性があります。
環境によっては、次の文言が表示されます。
FATAL: remaining connection slots are reserved for roles with privileges of the "pg_use_reserved_connections" role
これは、残りがpg_use_reserved_connectionsの権限を持つ役割とスーパーユーザー向けに確保されている状態です。
一方、sorry, too many clients alreadyまで進むと、接続処理に使える枠自体が残っていません。予約された権限を持つ利用者でも、新しい接続に失敗する可能性があります。予約枠の判定と文言はPostgreSQL本体のpostinit.cで確認できます。
接続数と設定値を確認する
まだ利用できる管理用接続や既存の管理画面がある場合は、最初に現在値を確認します。
SHOW max_connections;
SHOW superuser_reserved_connections;
reserved_connectionsに対応する環境では、次の値も確認してください。未対応の版では設定項目が存在しないため、エラーになります。
SHOW reserved_connections;
現在のクライアント接続数は、次のSQLで確認できます。
SELECT count(*) AS client_connections
FROM pg_stat_activity
WHERE backend_type = 'client backend';
pg_stat_activityにはサーバープロセスごとの状態が表示されます。PostgreSQL公式文書にも、現在の状態や問い合わせを確認する統計ビューとして説明されています。pg_stat_activityの公式資料
どの接続が枠を使っているか調べる
利用者、接続元、アプリケーション名、状態ごとに集計すると、接続が偏っている場所を絞れます。
SELECT
usename,
application_name,
client_addr,
state,
count(*) AS connections
FROM pg_stat_activity
WHERE backend_type = 'client backend'
GROUP BY usename, application_name, client_addr, state
ORDER BY connections DESC;
特に確認したい状態はidle in transactionです。これは、トランザクションを開いたまま、次の問い合わせを待っている接続を示します。
SELECT
pid,
usename,
application_name,
client_addr,
state,
xact_start,
state_change,
query
FROM pg_stat_activity
WHERE state = 'idle in transaction'
ORDER BY xact_start;
同じアプリケーション名や接続元から想定以上の接続が作られている場合は、アプリケーション側の接続上限と切断処理を確認してください。複数のアプリケーションを動かしているなら、それぞれの最大接続数の合計も確認します。
緊急時に不要な接続を終了する
接続枠を戻す必要がある場合は、既存の管理用接続から対象を確認します。いきなり一括終了せず、pid、利用者、状態、開始時刻、問い合わせを確認してください。
終了して問題ない接続を特定できた場合に限り、1件ずつ終了します。
SELECT pg_terminate_backend(12345);
12345は確認済みのpidへ置き換えます。処理中の接続を終了すると、その接続で進行中のトランザクションは取り消されます。自分自身の接続、複製、バックアップ、保守処理を誤って終了しないでください。
新しい管理用接続も作れない場合は、アプリケーションからの新規接続をいったん止め、既存の管理経路や接続を取りまとめる仕組みから不要な接続を閉じます。それも使えない場合、再起動は最後の手段です。実行前に停止時間と処理中トランザクションへの影響を確認してください。
接続を閉じない実装を修正する
接続を作るたびに新規接続を開き、処理後に返却または切断していないと、利用者が増えていなくても枠が埋まります。
アプリケーションでは、正常終了だけでなく例外発生時にも接続が返却される構造にします。接続プールを使う場合は、各アプリケーションの最大接続数、待ち時間、接続の寿命を確認してください。
たとえば、4つのアプリケーションがそれぞれ最大30接続を確保できる設定なら、合計は120接続です。PostgreSQL側の一般利用者向けの枠がこれより少なければ、負荷が重なったときに接続できなくなります。各設定を個別に見るだけでなく、同じPostgreSQLへ接続するすべての上限を合計して判断します。
idle in transactionを放置しない
トランザクションを開いたまま止まる接続が繰り返し発生する場合は、まずアプリケーションの処理を修正します。そのうえで、安全網としてidle_in_transaction_session_timeoutを設定できます。
特定のアプリケーション用の役割だけに設定する例は次のとおりです。
ALTER ROLE app_user
SET idle_in_transaction_session_timeout = '5min';
この変更は、その後に作成されるセッションへ適用されます。app_userと時間は、アプリケーションの正常な処理時間に合わせて変更してください。
この設定の既定値は0で、無効です。長時間開いたトランザクションはロックを保持する場合があり、不要になった行の掃除も妨げます。PostgreSQL公式の接続既定値では、表の肥大につながる可能性も説明されています。
トランザクション外の待機接続を終了するidle_session_timeoutもありますが、接続プールなどが予期しない切断へ対応できない場合があります。公式文書も、この設定を中間ソフトウェア経由の接続へ適用する際は注意するよう案内しています。
max_connectionsを上げる前に確認すること
max_connectionsは同時接続数の上限です。既定値は通常100ですが、initdbの判断により小さくなる場合があります。PostgreSQL公式の接続設定に仕様が記載されています。
値を増やせば受け付けられる接続数は増えますが、PostgreSQLはこの値に基づいて共有メモリを含む一部の資源を確保します。また、変更は設定の再読み込みだけでは反映されず、サーバーの再起動が必要です。
そのため、次の順序で判断します。まず不要な接続と接続漏れをなくし、各接続プールの合計上限を調整します。通常時と混雑時の接続数を測り、それでも正当な接続需要が上限を超える場合に、利用できるメモリと再起動手順を確認してmax_connectionsを見直してください。
予約接続枠を理解する
superuser_reserved_connectionsは、一般の接続で枠が埋まりかけたときにも管理者が接続できるよう、スーパーユーザー向けに枠を残す設定です。既定値は3です。
たとえばmax_connectionsが100、superuser_reserved_connectionsが3なら、一般の役割は通常97接続まで利用でき、その後の枠はスーパーユーザー向けになります。
reserved_connectionsは、pg_use_reserved_connectionsの権限を持つ役割向けに追加の予約枠を設ける設定です。既定値は0です。どちらもサーバー起動時に決まる設定であり、変更には再起動が必要です。
予約枠を減らして一般接続を増やすと、障害時に管理用接続を作れなくなる可能性があります。単に利用可能数を増やす目的で使い切らず、緊急時の調査経路を残してください。
近い接続エラーとの違い
could not connect to server: Connection refusedは、PostgreSQLの待ち受け先まで接続できていない状態です。サーバー停止、ポート、待ち受けアドレス、通信経路などを確認します。
password authentication failed for userは、PostgreSQLへ到達した後の認証失敗です。接続数ではなく、利用者名、パスワード、認証設定を確認してください。
number of requested standby connections exceeds "max_wal_senders"は、複製用の接続枠に関するエラーです。通常のアプリケーション接続とは分けて調査します。
解決手順のまとめ
最初にpg_stat_activityを利用者、接続元、アプリケーション名、状態ごとに集計します。不要な接続やidle in transactionが多ければ、対象を確認したうえで整理してください。
次に、アプリケーションが例外時にも接続を返しているか、複数の接続プールの上限合計が大きすぎないかを確認します。長時間放置されるトランザクションには、処理の修正とidle_in_transaction_session_timeoutを検討します。
max_connectionsの増加は最後に判断します。再起動と資源の増加を伴うため、接続数の原因を確認せずに変更しないでください。
免責事項:本記事の内容は一般的なPostgreSQL環境を前提としています。本番環境で接続の終了やサーバー設定の変更、再起動を行う前に、処理中のトランザクション、複製、バックアップ、停止時間への影響を確認してください。
この記事でエラーは解決しましたか?