pgpool-IIによるPostgreSQLの最適化:コネクションプーリング、ロードバランシング、キャッシングの実践的ソリューション

Database tutorial - IT technology blog
Database tutorial - IT technology blog

PostgreSQLが「ボトルネック」になる時

Node.jsからPythonまで、私がこれまで手掛けてきたプロジェクトで最も厄介だったエラーは、ロジックのバグではなく FATAL: remaining connection slots are reserved でした。デフォルトのPostgreSQLは、約100接続程度しか許可していません。トラフィックが急増すると、Postgresでは新しい接続ごとに個別のプロセスが作成され、1接続あたり2〜3MBのメモリを消費するため、サーバーのRAMがすぐに枯渇してしまいます。

多くの開発者はすぐに max_connections を増やそうと考えがちです。しかし、これは待機プロセスを管理するためにCPUを酷使することになるため、致命的な間違いです。PgBouncerはプーリングに適した選択肢ですが、ロードバランシングやクエリキャッシングを含む「オールインワン」のソリューションが必要な場合、pgpool-IIこそが最も有力な候補となります。

ピーク時に同時アクセス5,000ユーザーを抱えるECサイトで半年以上運用した経験から、pgpool-IIはデータベースクラスター全体を調整する「指揮者」のような、極めて重要な役割を果たすと実感しています。

pgpool-IIの「導入する価値がある」3つの機能

適切に設定するためには、pgpool-IIがどのようにデータフローに介成するかを理解する必要があります。

1. Connection Pooling(接続オーバーヘッドの削減)

接続のオープン/クローズを繰り返す(CPU負荷が高い)代わりに、pgpool-IIは古い接続を「プール」に保持します。アプリケーションから要求があると、利用可能な接続を即座に割り当てます。実測値では、認証のハンドシェイクをスキップできるため、各クエリのレイテンシが約15〜20%削減されました。

2. Load Balancing(読み取り/書き込みの負荷分散)

これはシステムを容易にスケールアウトさせる機能です。Primary-Standby構成の場合、pgpool-IIはSQL文を自動的に判別します。SELECT 文はStandbyノード(リードレプリカ)に振り分けられ、INSERT/UPDATE はPrimaryノードに集約されます。これにより、サブサーバーのハードウェアリソースを最大限に活用できます。

3. Query Caching(インテリジェントなキャッシュ)

pgpool-IIは SELECT の結果をメモリに保存します。計算に2〜3秒かかる複雑なクエリも、2回目以降の呼び出しではほぼ瞬時(数ミリ秒)に結果を返します。ただし注意点として、データの変動が少ないものに限定して使用すべきです。

実践的な設定ガイド

システムが以下の3つのノードで構成されていると仮定します:

  • Primary: 192.168.1.10 (Port 5432)
  • Standby: 192.168.1.11 (Port 5432)
  • pgpool-II: 192.168.1.20 (Port 9999 で待機)

ステップ1:クイックインストール

Ubuntuでのインストールは非常に簡単です:

sudo apt update && sudo apt install pgpool2 -y

ステップ2:データベースノードの定義

/etc/pgpool2/pgpool.conf を開きます。ここでシステムの「バックエンド」を定義します:

# メインノード (Primary)
backend_hostname0 = '192.168.1.10'
backend_port0 = 5432
backend_weight0 = 1
backend_flag0 = 'ALLOW_TO_FAILOVER'

# サブノード (Standby)
backend_hostname1 = '192.168.1.11'
backend_port1 = 5432
backend_weight1 = 1.5 # このノードの読み取り優先度を高く設定
backend_flag1 = 'ALLOW_TO_FAILOVER'

注意:backend_weight を使用してトラフィックを調整できます。Standbyサーバーのスペックが高い場合は、この数値を上げてより多くのクエリを処理させるようにします。

ステップ3:負荷分散モードの有効化

以下のパラメータを編集して、ロードバランシング機能を有効にします:

connection_cache = on
load_balance_mode = on
master_slave_mode = on
master_slave_sub_mode = 'stream' # ストリーミングレプリケーションを使用

本番環境で学んだ「現場の教訓」

pgpool-IIの導入は常にバラ色というわけではありません。これまでに直面した課題から得た3つの注意点を共有します:

  • リアルタイムデータへのキャッシュ使用を避ける: 顧客が支払いを完了した直後なのに、pgpool-IIがキャッシュから古い残高を返してしまったというトラブルがありました。アドバイス:キャッシュはカタログや記事などのマスタデータにのみ使用してください。
  • レプリケーション遅延(Replication Lag)の問題: Primaryに書き込まれたデータがStandbyに同期される前に、pgpool-IIがStandbyから読み取ってしまうと、データの一貫性が失われることがあります。delay_threshold を設定して、この遅延を制御してください。
  • ヘルスチェック: フェイルオーバースクリプトが正しく動作することを確認してください。Primaryノードがダウンした際、pgpool-IIはどのノードが昇格するかを正確に把握してトラフィックを再ルーティングし、システム全体のダウンを防ぐ必要があります。

動作確認の方法

サービスを再起動した後、psqlコマンドでpgpool-IIのポートに直接接続し、クラスターの状態を確認します:

psql -h 192.168.1.20 -p 9999 -U postgres -c "show pool_nodes"

すべてのノードの status カラムが up と表示されていれば、設定は成功です。

まとめ

直接接続からpgpool-IIへの移行は、アーキテクチャにおける大きな転換点となります。これにより、アプリケーションの耐負荷性能と安定性が向上し、将来的な拡張も容易になります。もしシステムが重い SELECT クエリによって遅くなり始めているなら、今すぐpgpool-IIの導入を検討してみてください。

Share: