世界を動かす技術を、日本語で。

PgBouncerのスループットを4倍にスケールアップしました

2026年7月12日原文(clickhouse.com)

概要

  • PgBouncerシングルスレッド 設計によるCPU利用の制限
  • so_reuseportプロセスフリート でCPUコアを有効活用
  • Peering でキャンセルリクエストの問題を解決
  • 実験結果 でスループットとリソース利用率の大幅向上を確認
  • ClickHouse Managed Postgres はこの構成を標準採用

PgBouncerのシングルスレッド制限とその回避策

  • PgBouncer は1プロセスで 1コア のみ利用、残りコアは未使用
  • 16 vCPUのマシンでは 1コアのみ がプーリング処理担当
  • so_reuseport を活用し、複数プロセスが同一ポートで待機
    • カーネルが 着信接続 を各プロセスに 自動分散
    • クライアントからは 単一エンドポイント に見える
  • プロセスごとにシングルスレッド、so_reuseportで 全コア活用

Peeringによるキャンセルリクエスト対応

  • Postgresのキャンセルリクエストは 新規接続 で送信
  • so_reuseport利用時、 別プロセス にリクエストが届く可能性
  • Peering 導入でプロセス間の 協調 実現
    • 間違ったプロセスに届いたキャンセルも 正しいプロセスへ転送
    • フリート全体で キャンセル処理 が機能

コネクションプール・リソース管理

  • トランザクションモード でプール運用
    • トランザクション終了時に 即座にコネクション返却
  • コネクション上限(max_client_conn, max_db_connections)
    • プロセス数で 均等分割
    • フリート全体で Postgresの過負荷防止

実験と性能比較

  • 16 vCPU c7i.4xlarge で検証
    • 1プロセス構成と16プロセス構成で比較
  • クライアント数: 8〜256でスループットとCPU利用率を測定
  • 1プロセス構成 :最大約87,000 TPSで頭打ち、256クライアント時は77,000 TPSに低下
    • CPU利用率 は1コア分(約97%)、全体では10%未満
  • 16プロセス構成 :最大約336,000 TPS、8コア分を利用
    • CPU利用率 は約52%、Postgresやロードジェネレータがボトルネックになるまで余力あり
  • CloudWatch でも同様の傾向
    • 1プロセス: 平均16% CPU利用
    • 16プロセス: 平均60% CPU利用

コネクション上限とスループットの違い

  • 1プロセス は自身のmax_client_conn超過で新規接続拒否
  • フリート構成 は上限を分散しつつ、 全体で高い接続数 を実現

適用と推奨構成

  • 少数接続時は 1プロセス でも十分
  • 高並列時は フリート構成 が圧倒的に有利
  • ClickHouse Managed Postgres は標準でこの構成を採用
    • Postgresプロビジョン時 に自動的に有効

まとめ

  • PgBouncerシングルスレッド制限 はso_reuseportとプロセスフリートで解消
  • Peering でキャンセルリクエストも正しく処理
  • 高並列・高負荷環境 では フリート構成 が必須
  • ClickHouse Managed Postgres で最適なコネクションプーリング環境を実現

Hackerたちの意見

面白いね。うちはKubernetesでpgbouncerを動かしてるから、1台のマシンで複数のpgbouncerプロセスを立てるのは簡単だったよ。複数のマシンで動かすのも簡単で、Azureで運用してるから、VMのメンテナンスでローリングアウトageを引き起こされるのを防ぐのに役立ってるんだ。

なるほど、納得。pgbouncerからPostgresへのネットワークホップが追加されることでスループットにどう影響するのかすごく気になる。少しの違いがあると思ってるけど、やっぱり興味あるな。

これは実用よりも楽しみのためにやったことなんだけど、rqbitのBitTorrentクライアントに似たようなものをハッキングするのがすごく楽しかった。各トレントごとに'rqbit download'のインスタンスをso_reuseport経由で動かしたかったんだ。ピアが接続しようとすると、ランダムなインスタンスに送られる仕組み。だから、インスタンス同士が見つけ合って、データをプロキシしたり、ソケットを直接渡し合ったりして、必要なインスタンスにピアソケットを渡すための全体的なランデブーシステムを作った。インスタンス間の通信にはポストカードRPCを使ってる。Clickhouseのso_reuseportのランデブーのニーズは明らかに全然違うけど、こういうso_reuseportの調整が見られるのは楽しいね(もっと実用的な用途のためにね)!異なるアプリが使えるような一般的なピアリングプロトコルがあったらすごく面白いだろうな。この全体の実験は、正直言って自分のアプリには無駄だったけど、楽しい道を歩けたよ。だから、広い意味でのプロトコルが何のためにあるのか、実際に何に使うのかはよくわからない。でも、すごくクールなアイデアだと思う!共有のTursoデータベースは、RPCシステムよりも実用的かもしれないね。ハハ。 https://github.com/rektide/rqbit/tree/peering

HAProxyと複数のPGBouncerインスタンスを使うことにデメリットはあったの?

SO_REUSEPORTは、カーネル空間で必要なことをほぼ全部やってくれるから、無駄なユーザー空間のホップがないんだ。これらは同じVM上で動いてるよ: https://lwn.net/Articles/542629

ただhttps://github.com/yandex/odysseyを使えばいいよ :) スケーラブルなPgBouncerだよ。

面白い(半分関連)な事実だけど、ClickHouseはもともとYandexによって開発されたんだ :)

最初に、Postgresに最も実績のあるネイティブな選択肢であるPgBouncerから始めて、適切に調整してみたんだ。準備済みステートメントのサポートみたいな長い間の問題も解決されたし、すごくうまく動いてるよ。10K以上のPostgres接続でスケールしてるお客さんもたくさんいるし、今後はodysseyやpgdogみたいな他の選択肢も考えてみるつもり!ちなみに、10K以上の接続をPostgresで持つのはあまり好きじゃないんだ。100接続あれば十分にスケールできると思うけど、それはまた別の話だね。 ;)

yandexはロシアの会社だから、使わない方がいいよ。

俺はpgdog(https://github.com/pgdogdev/pgdog)を使ってるけど、すごくうまくいってるよ!

了解、将来的にpgdogを提供することも考えてるよ!なぜpgbouncerを選んだのかについての詳しい情報はここで見てね https://news.ycombinator.com/item?id=48873867

気に入ってもらえて嬉しいよ。これは、何年も前にInstacartで直面したPgBouncerのいくつかの欠点を解決するために作られたもので、Postgresを水平にスケールさせるためのより強固な基盤を持つためなんだ(それがシャーディングだよ)!

Hacker Newsで議論の続きを見る