pgBouncer on Ubuntu — PostgreSQLコネクションプーリングの設定

データベース

PostgreSQLに100本のコネクションが来ると、サーバーのメモリが一気に逼迫します。pgBouncer は「コネクションプーリング」でこの問題を解決するミドルウェアで、アプリ側は100接続していても、実際にPostgreSQLに渡す接続を20本以下に抑えられます。

Ubuntu 24.04 LTS では apt install pgbouncer 一発でインストールでき、設定ファイルを2〜3行書くだけで動き始めます。本記事では、ubuntu:24.04 の Docker コンテナで実際にインストール・起動を行い、その実ログと設定ファイルの中身を余すことなくお見せします。

この記事のポイント

  • Ubuntu 24.04 では apt install pgbouncerpgBouncer 1.22.0 が入る(2026-06-13 実測)
  • デフォルトのリスンポートは 6432。アプリの接続先をこのポートに変えるだけで動く
  • Webアプリには pool_mode = transaction が最適。デフォルトの session から変更する
  • userlist.txt にユーザーとMD5ハッシュを書くのがつまずきポイント。手順を丁寧に解説
  • Ubuntu 22.04 は 1.16.1 だが、24.04 は 1.22.0 と大きくアップしている

目次

  1. pgBouncer とは?なぜ必要か
  2. Ubuntu 24.04 へのインストール手順
  3. pgbouncer.ini の設定
  4. userlist.txt の作り方
  5. 起動と動作確認
  6. SHOW コマンドでプールの状態を確認
  7. pool_mode の選び方
  8. よくあるエラーと解決策
  9. まとめ

pgBouncer とは?なぜ必要か

PostgreSQL は接続ごとにプロセスを fork します。接続が増えるほどメモリ消費が増え、1,000接続ともなると数 GB のメモリが接続のためだけに使われます。

pgBouncer はアプリと PostgreSQL の間に立つ軽量な接続プロキシです。アプリは pgBouncer(ポート 6432)に接続し、pgBouncer は必要なときだけ PostgreSQL(ポート 5432)への接続を確立します。接続数を大幅に削減できるので、特にコネクション数が多くなりがちな Web アプリや API サーバーに効果的です。

Ubuntu 22.04/24.04 での pgBouncer・PostgreSQL パッケージバージョン比較(実測)
Ubuntu 22.04/24.04 での pgBouncer・PostgreSQL パッケージバージョン比較(実測)

上の表は ubuntu:22.04ubuntu:24.04 の公式 Docker イメージで apt-cache policy pgbouncer を実行した結果です。Ubuntu 24.04 では pgBouncer 1.22.0 が標準リポジトリから入ります(Ubuntu 22.04 は 1.16.1)。PostgreSQL も 14 から 16 に上がっており、最新環境で始めるなら 24.04 が断然おすすめです。

Ubuntu 24.04 へのインストール手順

注意

本記事のコマンドは Ubuntu 24.04 LTS(Docker公式イメージ ubuntu:24.04)で検証しています。Ubuntu 22.04 では pgBouncer のバージョンが 1.16.1 と異なります。

手順1:パッケージリストを更新する




ubuntu@linuxlab: ~
$ sudo apt update
Hit:1 http://ports.ubuntu.com/ubuntu-ports noble InRelease
Hit:2 http://ports.ubuntu.com/ubuntu-ports noble-updates InRelease
Reading package lists… Done

apt update を忘れると古いキャッシュから検索してしまい、最新バージョンが入らないことがあります。必ず最初に実行してください。

手順2:pgBouncer をインストールする




ubuntu@linuxlab: ~
$ sudo apt install -y pgbouncer
Reading package lists… Done
Building dependency tree… Done
The following NEW packages will be installed:
pgbouncer python3 python3-dbus python3-gi networkd-dispatcher …
Setting up pgbouncer (1.22.0-1build4) …
Created symlink /etc/systemd/system/multi-user.target.wants/pgbouncer.service
→ /usr/lib/systemd/system/pgbouncer.service.

インストールが完了すると、systemd サービスが自動で登録されます。設定ファイル /etc/pgbouncer/pgbouncer.ini と認証ファイル /etc/pgbouncer/userlist.txt も自動で作成されます。

手順3:バージョンを確認する




ubuntu@linuxlab: ~
$ pgbouncer –version
PgBouncer 1.22.0
libevent 2.1.12-stable
adns: c-ares 1.27.0
tls: OpenSSL 3.0.13 30 Jan 2024
systemd: yes

ubuntu:24.04 の Docker コンテナで実際に確認した出力です。PgBouncer 1.22.0 が入り、systemd: yes と表示されていることからシステムの systemd と連携できることがわかります。

pgBouncer 1.22.0 インストール・起動ログ(実測・ubuntu:24.04)
pgBouncer 1.22.0 インストール・起動ログ(実測・ubuntu:24.04)

手順4:設定ファイルの場所を確認する




ubuntu@linuxlab: ~
$ ls -la /etc/pgbouncer/
total 24
drwxr-xr-x 2 root root 4096 Jun 13 13:08 .
drwxr-xr-x 1 root root 4096 Jun 13 13:08 ..
-rw-r—– 1 postgres postgres 10446 Apr 16 2024 pgbouncer.ini
-rw-r—– 1 postgres postgres 0 Apr 16 2024 userlist.txt

両ファイルのオーナーは postgres ユーザーです。pgbouncer.ini は約10KB のコメント入り設定ファイルで、userlist.txt は空の状態で作成されます。

pgbouncer.ini の設定

設定ファイルは3つのセクションに分かれています。最低限押さえるべき設定を解説します。

pgBouncer 1.22.0 主要パラメータ一覧(実測・ubuntu:24.04)
pgBouncer 1.22.0 主要パラメータ一覧(実測・ubuntu:24.04)

①[databases] セクション — 接続先DBを指定する




ubuntu@linuxlab: /etc/pgbouncer/pgbouncer.ini
$ sudo nano /etc/pgbouncer/pgbouncer.ini
[databases]
mydb = host=127.0.0.1 port=5432 dbname=mydb

[databases] セクションに「pgBouncer 側の DB 名 = 接続先」を書きます。上の例では、アプリが mydb という名前で接続してくると、pgBouncer が 127.0.0.1:5432mydb データベースへ転送します。

②[pgbouncer] セクション — 主要パラメータ

デフォルトの /etc/pgbouncer/pgbouncer.ini で有効になっている設定(コメントアウトなし)は以下の通りです(ubuntu:24.04 で確認):




ubuntu@linuxlab: pgbouncer.ini 最小設定例
[pgbouncer]
logfile = /var/log/postgresql/pgbouncer.log
pidfile = /var/run/postgresql/pgbouncer.pid
listen_addr = localhost
listen_port = 6432
unix_socket_dir = /var/run/postgresql
auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt
; 変更推奨: pool_mode = transaction
; max_client_conn = 100
; default_pool_size = 20

デフォルトでは listen_addr = localhost かつ listen_port = 6432 でローカルのみ受け付けます。外部からの接続を受け付けたい場合は listen_addr = * に変更し、ファイアウォールも合わせて設定してください。

pool_mode はデフォルト session のまま?

pgbouncer.inipool_mode はデフォルトでコメントアウト(= session)です。Webアプリで使うなら pool_mode = transaction に変更することを強くおすすめします。ただし、SET 文や LISTEN/NOTIFY、プリペアドステートメントはトランザクション外では使えなくなります。

userlist.txt の作り方

ここが最もつまずきやすいポイントです。pgBouncer は独自の認証ファイル userlist.txt を使います。いちばん確実なのは、PostgreSQL の pg_shadow に保存されているパスワード文字列をそのままコピーする方法です。これなら次に説明する md5/SCRAM のどちらでも確実に一致します。

Ubuntu 24.04 + PostgreSQL 16 は「md5」ではなく「SCRAM」がデフォルト

古い解説記事の多くは md5 ハッシュを前提にしていますが、PostgreSQL 16(Ubuntu 24.04 標準)の password_encryption デフォルトは scram-sha-256 です。そのため pg_shadow に入っているのは md5... ではなく SCRAM-SHA-256$... という文字列です。これを実際に ubuntu:24.04 のコンテナで確認しました。

pg_shadow からパスワード文字列を取得する




ubuntu@linuxlab: ~ (psql セッション)
$ sudo -u postgres psql -tAc “SELECT passwd FROM pg_shadow WHERE usename=’pgtest’;”
SCRAM-SHA-256$4096:CvgXxA528MXV41DHPFKGQA==$VDuUTeDM…:ExJRujnY…

取得した値を /etc/pgbouncer/userlist.txt に以下の形式で書きます(ユーザー名・パスワード文字列の両方をダブルクォートで囲むのがポイント):




ubuntu@linuxlab: /etc/pgbouncer/userlist.txt
“pgtest” “SCRAM-SHA-256$4096:CvgXxA528MXV41DHPFKGQA==$VDuUTeDM…:ExJRujnY…”

このとき pgBouncer 側は auth_type = md5 のままで構いません。auth_type = md5 は「md5 または SCRAM の格納形式を自動で扱う」設定なので、pg_shadow の SCRAM 文字列をそのまま貼れば認証が通ります。実際にこの手順で、6432 ポート経由の接続が成功するのを確認しました(前掲の SELECT version())。

md5 でユーザーを作っている場合

古い設定(password_encryption = md5)でユーザーを作っている、あるいは互換性のため md5 で揃えたい場合は、シェルで md5 ハッシュを計算して書けます:




ubuntu@linuxlab: ~
$ echo -n “mypasswordmyuser” | md5sum
a1b2c3d4e5f6789012345678901234ab –
# パスワード+ユーザー名を連結して md5 を計算
$ echo ‘”myuser” “md5a1b2c3d4e5f6789012345678901234ab”‘ | sudo tee /etc/pgbouncer/userlist.txt

PostgreSQL の MD5 認証は「パスワード + ユーザー名」を連結した文字列のハッシュです。パスワードだけのハッシュでは認証が通りませんので注意してください。ただし前述の通り PostgreSQL 16 のデフォルトは SCRAM なので、まずは pg_shadow の値をそのままコピーする方法を試すのが確実です。

起動と動作確認

手順1:pgBouncer を起動する




ubuntu@linuxlab: ~
$ sudo systemctl enable –now pgbouncer
Created symlink /etc/systemd/system/multi-user.target.wants/pgbouncer.service
→ /usr/lib/systemd/system/pgbouncer.service.

enable --now自動起動の有効化と即時起動を同時に行えます

手順2:サービス状態を確認する

systemd で動いている VPS では、systemctl status で稼働状態を確認できます(以下は systemd ホストでの表示例です):




ubuntu@linuxlab: ~
$ sudo systemctl status pgbouncer
● pgbouncer.service – connection pooler for PostgreSQL
Loaded: loaded (/usr/lib/systemd/system/pgbouncer.service; enabled)
Active: active (running)
Main PID: 6238 (pgbouncer)
Tasks: 2
Memory: 2.6M

Active: active (running) と表示されていれば起動成功です。systemd を PID 1 で持たない Docker コンテナでは、代わりに ps で直接プロセスを確認しました。ubuntu:24.04 コンテナでの実出力です:




ubuntu@linuxlab: ~ (ubuntu:24.04 コンテナ・実測)
$ ps -o pid,rss,vsz,comm -C pgbouncer
PID RSS VSZ COMMAND
6238 2628 21248 pgbouncer

RSS(実メモリ)は 約2.6MB(2628KB)。pgBouncer は非常に軽量な常駐プロセスであることが実測からも分かります。

続いて、実際に ubuntu:24.04 のコンテナで pgBouncer を起動したときのログです(/var/log/postgresql/pgbouncer.log の実出力):




ubuntu@linuxlab: /var/log/postgresql/pgbouncer.log
2026-06-13 13:22:21.965 UTC [6189] LOG listening on unix:/var/run/postgresql/.s.PGSQL.6432
2026-06-13 13:22:21.968 UTC [6189] LOG process up: PgBouncer 1.22.0, libevent 2.1.12-stable (epoll), adns: c-ares 1.27.0, tls: OpenSSL 3.0.13 30 Jan 2024

起動直後に process up: PgBouncer 1.22.0 と出れば正常です。Unix ソケット(/var/run/postgresql/.s.PGSQL.6432)と TCP(ポート 6432)の両方でリッスンします。

手順3:接続テストをする

ubuntu:24.04 のコンテナで PostgreSQL(testdb / ユーザー pgtest)を起動し、pgBouncer の 6432 ポート経由で接続した実出力です:




ubuntu@linuxlab: ~
$ psql -h 127.0.0.1 -p 6432 -U pgtest -d testdb -c “SELECT version();”
version
———————————————————————————————–
PostgreSQL 16.14 (Ubuntu 16.14-0ubuntu0.24.04.1) on aarch64-unknown-linux-gnu, compiled by
gcc (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0, 64-bit
(1 row)

PostgreSQL の 5432 ではなく、pgBouncer の 6432 ポートに接続しているのに、ちゃんと PostgreSQL 16.14 が返ってきました。アプリの接続先をこのポートに変えるだけで、コネクションプーリングが有効になります。

SHOW コマンドでプールの状態を確認

pgBouncer には管理用の仮想データベース pgbouncer があります。SHOW コマンドでプールの状態をリアルタイムに確認できます(管理コンソールに入るには、設定ファイルの admin_users / stats_users にユーザーを登録しておきます)。

ここからは 実際にプーリングが効いている瞬間を見せます。ubuntu:24.04 のコンテナで pool_mode = transactiondefault_pool_size = 5 に設定し、12 本のクライアントから同時にトランザクションを投げた状態で SHOW POOLS; を実行した実出力です(列は見やすいよう一部抜粋):




ubuntu@linuxlab: pgbouncer=# (12クライアント同時実行中)
$ psql -h 127.0.0.1 -p 6432 -U pgtest -d pgbouncer -c “SHOW POOLS;”
database | user | cl_active | cl_waiting | sv_active | sv_idle | maxwait | pool_mode
———-+——–+———–+————+———–+———+———+————-
testdb | pgtest | 5 | 7 | 5 | 0 | 1 | transaction
(1 row)

この出力の見方:

  • cl_active:いまクエリを処理中のクライアント数(5本)
  • cl_waiting:サーバー接続の空きを待っているクライアント(7本)
  • sv_active:PostgreSQL に実際に張っている接続数(5本だけ
  • maxwait:いちばん長く待っているクライアントの待機秒数

クライアントは合計 12 本(処理中5 + 待機7)接続しているのに、PostgreSQL への実接続は default_pool_size で決めた 5 本で打ち止めになっています。残り7本は順番待ちで、空いた接続を使い回します。これがコネクションプーリングの効果で、12本のクライアントを5接続でさばけているわけです。SHOW CLIENTS; で数えると確かに 12 行返ってきました。

トランザクションがすべて終わると、サーバー接続は sv_idle(アイドル)としてプールに残り、次の接続に再利用されます。続いて累積統計を SHOW STATS; で確認します(縦表示 -x・抜粋):




ubuntu@linuxlab: pgbouncer=#
$ psql -h 127.0.0.1 -p 6432 -U pgtest -d pgbouncer -x -c “SHOW STATS;”
-[ RECORD 2 ]—–+———-
database | testdb
total_xact_count | 13
total_query_count | 13
total_received | 503
total_sent | 1466
avg_xact_time | 9746334
$ psql -h 127.0.0.1 -p 6432 -U pgtest -d pgbouncer -c “RELOAD;”
RELOAD

SHOW STATS; でトランザクション数(total_xact_count)・クエリ数・転送バイト数(total_received / total_sent)などの累積統計が見られます。avg_xact_time はマイクロ秒単位の平均トランザクション時間です。設定変更後は RELOAD; で設定を再読み込みできます(pgBouncer を再起動する必要はありません)。

pool_mode の選び方

pgBouncer pool_mode 3種類の比較表
pgBouncer pool_mode 3種類の比較表

pgBouncer の pool_mode は3種類あります。接続の解放タイミングが違い、アプリへの影響も大きく変わります。

  • session(デフォルト):クライアントが切断したときにサーバー接続を解放。既存アプリを変更せずに使えますが、接続節約効果は低めです。最初の移行先として安全。
  • transaction(Webアプリに推奨):トランザクション終了後に解放。接続節約効果が高く、Webアプリやマイクロサービスとの相性が最も良いモードです。ただし SETLISTEN/NOTIFYPREPARE はトランザクション外では使えません。
  • statement:SQL ステートメント終了後に解放。制約が多すぎるため実用上はほぼ使われません。

新規で構築するWebアプリには transaction を選び、既存アプリを移行する場合はまず session で動作確認してから transaction に移行するのが安全です。

pgBouncer セットアップチェックリスト
pgBouncer セットアップチェックリスト

よくあるエラーと解決策

①「no such database」— データベース名が一致しない




ubuntu@linuxlab: ~
psql: error: connection to server at “127.0.0.1”, port 6432 failed: FATAL: no such database: testdb

pgbouncer.ini[databases] セクションに接続先 DB の設定がないか、DB 名のタイポです。設定後は sudo systemctl reload pgbouncer または管理 DB で RELOAD; を実行してください。

②「auth failed for user」— 認証エラー




ubuntu@linuxlab: ~
psql: error: connection to server at “127.0.0.1”, port 6432 failed: FATAL: password authentication failed for user “myuser”

userlist.txt の MD5 ハッシュが正しくない場合です。PostgreSQL の MD5 は「パスワード+ユーザー名」の連結ハッシュなので、パスワードだけの MD5 では通りません。pg_shadow から直接取得した値を使うのが確実です。

③「client_login_timeout (server down)」— バックエンドが落ちている

pgBouncer のログに以下のエラーが出る場合:




ubuntu@linuxlab: pgbouncer.log(実ログ)
2026-06-13 13:22:24.117 UTC [6189] LOG S-0xaaaa…: testdb/pgtest@127.0.0.1:5432 closing because: connect failed (age=0s)
2026-06-13 13:23:24.297 UTC [6189] WARNING C-0xaaaa…: testdb/pgtest@127.0.0.1:40296 pooler error: client_login_timeout (server down)

これは pgbouncer.ini に書いたホスト・ポートで PostgreSQL が動いていない状態です。実際に ubuntu:24.04 のコンテナで pgBouncer の起動ログを取得した際に確認した実ログです。service postgresql status で PostgreSQL の起動状態を確認してください。

④設定変更が反映されない

設定ファイルを変更した後は再起動ではなく reload で済みます:




ubuntu@linuxlab: ~
$ sudo systemctl reload pgbouncer
# または管理DBで
$ psql -p 6432 pgbouncer -c “RELOAD;”
RELOAD

まとめ

Ubuntu 24.04 での pgBouncer セットアップをまとめます(ubuntu:24.04 Docker コンテナで実際に確認した手順です)。

まとめ

  • apt install pgbouncerpgBouncer 1.22.0 が入る(Ubuntu 22.04 は 1.16.1)
  • 設定ファイルは /etc/pgbouncer/pgbouncer.ini。デフォルトのリスンポートは 6432
  • Webアプリには pool_mode = transaction を設定する
  • userlist.txt の MD5 ハッシュは「パスワード+ユーザー名」連結のハッシュ
  • 起動後は SHOW POOLS; で接続プールの状態をリアルタイム確認できる
  • 設定変更は RELOAD; のみで反映。再起動不要
著者アイコン
著者アイコン

pgBouncer のセットアップで一番詰まるのは userlist.txt のMD5ハッシュ形式です。pg_shadow から直接コピーするのが確実で、手動計算だとパスワード+ユーザー名の順番を間違えがちです。

本格的に PostgreSQL を運用するなら、VPS 上に専用サーバーを立てるとパフォーマンスが格段に上がります。VPS 各社の性能比較は以下の記事で実測データを紹介しています。

[LINK_bench_vps ARTICLE]

コメント

タイトルとURLをコピーしました