PostgreSQLコネクション枯渇(FATAL: sorry, too many clients)とPgBouncer構築

PostgreSQL Database DevOps Performance
結論

コネクション溢れを防ぐため手前に PgBouncer を挟み Transaction Mode でプーリングします。

# PgBouncer 公式仕様:pgbouncer.ini の基本設定例
[databases]
app_db = host=127.0.0.1 port=5432 dbname=app_production

[pgbouncer]
listen_addr = *
listen_port = 6432
auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt

# ⭕ トランザクション完了時に即座に接続を他のクライアントへ明け渡す最重要設定
pool_mode = transaction
max_client_conn = 10000
default_pool_size = 20

PostgreSQL公式仕様:プロセスモデルと max_connections の限界

PostgreSQL公式ドキュメント(postgresql.org/docs/current/server-setup.html)で説明されている通り、PostgreSQL は接続ごとに独立した OS プロセス(Process per Connection)を生成します。

  • 接続あたりのメモリ消費: 1接続あたり数MBのRAMを消費
  • max_connections の限界: 接続上限を単に max_connections = 1000 に引き上げると、CPUコンテキストスイッチとメモリ消費によりDB全体のパフォーマンスが著しく低下します。

実際に起こる障害:FATAL: sorry, too many clients already による全画面ダウン事故

Vercel や AWS Lambda などのサーバーレス環境、または大量の Web サーバーコンテナからデータベースへ直接接続している環境において、突発的なアクセススパイク(Auto Scaling 等)が発生した場合、以下のエラーが出現します。

FATAL: sorry, too many clients already

PostgreSQL の max_connections(デフォルト 100)を使い果たした瞬間、新たなDB接続が1件も通らなくなり、Webサイト全体の全ページで 500 エラー(DB Connection Refused)が多発する大障害 が発生します。


解決手順

  1. アプリケーションと PostgreSQL の中間に PgBouncer(軽量コネクションプーラー)をデプロイする
  2. pgbouncer.inipool_mode = transaction を設定し、クエリ処理が終わった瞬間に接続を別クライアントへ自動返却させる
  3. PostgreSQL 側の max_connections は 50〜100 に抑えつつ、PgBouncer 側で数千〜数万の同時クライアント(max_client_conn = 10000)を吸収させる