PgBouncer を用いた高トラフィックアプリケーションの PostgreSQL 接続プール構成

PostgreSQL の接続プールに PgBouncer を使用すると、数千の同時接続を処理し、リソースのオーバーヘッドを削減し、アプリケーションのパフォーマンスを劇的に向上させることができます

PgBouncerを使用したPostgreSQL接続プーリングの高トラフィックアプリケーション向け設定

はじめに

PostgreSQLデータベースが高い接続数に直面すると、パフォーマンスが急速に低下する可能性があります。各データベース接続はシステムリソースを消費し、PostgreSQLには同時接続数に実用的な制限があります。軽量な接続プーラーであるPgBouncerは、データベース接続のプールを維持し、それらをクライアントアプリケーションに効率的に配布することでこの問題を解決します。

接続プーリングの重要性

接続の問題

  • リソースオーバーヘッド: 各PostgreSQLバックエンドプロセスは5-10MBのメモリを消費
  • 接続制限: デフォルトのmax_connectionsは通常100-200
  • 起動コスト: 新しい接続の作成には1-5msかかる
  • コンテキストスイッチング: プロセスが多すぎるとCPUスラッシングが発生

PgBouncerの利点

  • データベース接続数を10-100倍削減
  • 最小限のオーバーヘッドで数千のクライアント接続を可能にする
  • ピーク時の接続キューイングを提供
  • さまざまなユースケースに対応する複数のプーリングモードをサポート

インストールと基本設定

PgBouncerのインストール

Ubuntu/Debianの場合:

sudo apt update
sudo apt install pgbouncer

CentOS/RHELの場合:

sudo yum install pgbouncer

macOSの場合:

brew install pgbouncer

ディレクトリ構造

/etc/pgbouncer/
  ├── pgbouncer.ini        # メイン設定
  └── userlist.txt         # 認証資格情報

設定ファイルのセットアップ

基本的なpgbouncer.ini設定

[databases]
; database_name = host=hostname port=5432 dbname=actual_db
myapp = host=localhost port=5432 dbname=production_db

[pgbouncer]
; 接続プーリングモード
pool_mode = transaction

; 最大接続数
max_client_conn = 1000
default_pool_size = 25
reserve_pool_size = 5
reserve_pool_timeout = 3

; ネットワーキング
listen_addr = 0.0.0.0
listen_port = 6432

; 認証
auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt

; ログ
log_connections = 1
log_disconnections = 1
log_pooler_errors = 1

; パフォーマンス
max_prepared_statements = 0

プーリングモードの理解

1. セッションプーリング (pool_mode = session)

  • 動作: クライアントにセッション全体にわたって接続を割り当て
  • ユースケース: 一時テーブルや準備済みステートメントを使用するアプリケーション
  • 効率: 低い (1:1の接続比率)
pool_mode = session

2. トランザクションプーリング (pool_mode = transaction) - 推奨

  • 動作: 各トランザクション後に接続をプールに戻す
  • ユースケース: 短いトランザクションを持つほとんどのウェブアプリケーション
  • 効率: 高い (10-100倍の削減)
pool_mode = transaction
default_pool_size = 25
max_client_conn = 1000

3. ステートメントプーリング (pool_mode = statement)

  • 動作: 各ステートメント後に接続を戻す
  • ユースケース: トランザクションなしの単純な読み取り専用クエリ
  • 効率: 最大 (ただし非常に制限的)
pool_mode = statement
; 注意して使用 - マルチステートメントトランザクションを壊す

認証設定

userlist.txtの作成

PgBouncerには別の認証ファイルが必要です。MD5ハッシュを生成し、userlist.txtに追加します。

userlist.txtの例:

"app_user" "md5d8578edf8458ce06fbc5bb76a58c5ca4"
"readonly_user" "md5a3c7f5e89d24e7c8b1f9d2e4a6c8b0d2"

PostgreSQL auth_queryの使用 (高度)

認証のためにPostgreSQLを直接クエリします:

auth_type = md5
auth_query = SELECT usename, passwd FROM pg_shadow WHERE usename=$1

高トラフィック向けの最適設定

接続プールのサイズ設定

プールサイズの公式:

default_pool_size = (num_cores × 2) + effective_spindle_count

4コアサーバーでSSDの場合:

default_pool_size = 20
reserve_pool_size = 5
max_client_conn = 1000

完全な本番設定

[databases]
production = host=db.example.com port=5432 dbname=prod_db pool_size=30
analytics = host=db-replica.example.com port=5432 dbname=prod_db pool_size=15

[pgbouncer]
pool_mode = transaction

; 接続制限
max_client_conn = 2000
default_pool_size = 25
min_pool_size = 10
reserve_pool_size = 8
reserve_pool_timeout = 3
server_lifetime = 3600
server_idle_timeout = 600

; ネットワーキング
listen_addr = 0.0.0.0
listen_port = 6432
so_reuseport = 1
pkt_buf = 8192

; セキュリティ
auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt
ignore_startup_parameters = extra_float_digits,options

; ログ
log_connections = 1
log_disconnections = 1
log_pooler_errors = 1
stats_period = 60

; パフォーマンス
max_prepared_statements = 0
query_timeout = 30
query_wait_timeout = 120

アプリケーション接続文字列

PgBouncer前

# 直接PostgreSQL接続
DATABASE_URL = "postgresql://user:[email protected]:5432/mydb"

PgBouncer後

# PgBouncer経由で接続
DATABASE_URL = "postgresql://user:[email protected]:6432/mydb"

モニタリングと管理

管理コンソールコマンド

PgBouncer管理コンソールに接続:

psql -h localhost -p 6432 -U pgbouncer pgbouncer

必須コマンド:

-- プール統計を表示
SHOW POOLS;

-- アクティブ接続を表示
SHOW CLIENTS;
SHOW SERVERS;

-- 設定を表示
SHOW CONFIG;

-- 設定をリロード
RELOAD;

一般的な問題のトラブルシューティング

問題1: "no more connections allowed"

解決策:

max_client_conn = 5000
default_pool_size = 50

問題2: 高いcl_waitingカウント

解決策:

  1. プールサイズを増やす
  2. 遅いクエリを最適化
  3. リザーブプールを追加

問題3: 準備済みステートメントエラー

解決策:

max_prepared_statements = 0

パフォーマンスへの影響例

PgBouncer前

  • 500同時リクエスト → 500PostgreSQL接続
  • データベース負荷: 95% CPU、8GB RAM
  • 応答時間: 平均250ms

PgBouncer後

  • 500同時リクエスト → 25PostgreSQL接続
  • データベース負荷: 35% CPU、1GB RAM
  • 応答時間: 平均80ms
  • 結果: 3倍高速、70%リソース使用量削減

結論

PgBouncerはPostgreSQLアプリケーションのスケーリングに不可欠です。接続オーバーヘッドを90%以上削減し、10-100倍のクライアントをサポートし、応答時間を劇的に改善します。トランザクションプーリングモードから始めて、モニタリングに基づいて調整してください。