使用 SO_REUSEPORT 與 Peering 將 PgBouncer 吞吐量提升 4 倍

使用 SO_REUSEPORT 與 Peering 將 PgBouncer 吞吐量提升 4 倍

ClickHouse 讓 PgBouncer 吞吐量提升 4 倍

ClickHouse 透過在單一機器上同時執行多個 PgBouncer 程序,將 PgBouncer 的吞吐量提升了 4 倍。此做法克服了 PgBouncer 單執行緒的特性(通常只能利用單一 CPU 核心),藉由使用 SO_REUSEPORT socket 選項,將連線負載分散到多個程序上。

使用 SO_REUSEPORT 進行負載分散

為了達到高吞吐量,ClickHouse 採用了 SO_REUSEPORT。此 socket 選項允許多個程序綁定到相同的 IP 位址與埠號。Linux 核心會以輪詢或雜湊的方式將進入的 TCP 連線分配給各個程序。這實質上把單一的 PgBouncer 實例變成多程序架構,使系統能隨著分配給程序池的 CPU 核心數線性擴展。

以 Peering 解決查詢取消問題

雖然 SO_REUSEPORT 能分散連線,但也帶來一個挑戰:查詢取消請求可能會落在不擁有該會話的 PgBouncer 程序上。因為標準的 PgBouncer 架構是相互隔離的,若一個程序收到它不認識的會話的取消請求,通常會直接忽略,導致查詢取消失敗。

為了解決此問題,ClickHouse 實作了 peering 機制。Peering 讓 PgBouncer 程序之間可以互相通訊。當一個程序收到它不擁有的會話的取消請求時,會將請求轉發給實際管理該會話的同儕程序。如此即可確保查詢取消在分散的程序池中仍能正常運作。

實作與設定

根據社群討論,這套配置需要啟用 so_reuseport 並定義 peer ID 與對應的 socket。以下是一個範例設定結構:

[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 6432
so_reuseport = 1
peer_id = 1
unix_socket_dir = /tmp/pgbouncer1

[peers]
1 = host=/tmp/pgbouncer1
2 = host=/tmp/pgbouncer2
3 = host=/tmp/pgbouncer3
4 = host=/tmp/pgbouncer4

社群見解與替代方案

關於此實作的技術討論指出了幾個替代方案與考量點,以便在 PostgreSQL 連線池上進行擴充:

  • 替代的連線池工具: 有使用者建議改用 Odysseypgdog 作為可擴充的 PgBouncer 替代方案。
  • 基礎設施層面的擴充: 透過 Kubernetes 部署多個 PgBouncer 實例,被視為在多台機器上取得類似效果的直接方式,亦能降低雲端服務供應商 VM 維護所帶來的風險。
  • 架構問題: 有工程師質疑此方式相較於使用傳統的 HAProxy 來分散流量至多個 PgBouncer 實例的優勢。

"取消請求落在從未見過該查詢的程序上,什麼也不會發生。Peering 解決了這個問題。各程序彼此知道對方的存在,若取消請求落在錯誤的程序上,會被轉發到真正擁有該會話的程序。"

此 peering 機制對於在多程序 PgBouncer 環境中維持 PostgreSQL 連線管理功能至關重要。


摘要: ClickHouse 透過在單機上部署多個 PgBouncer 程序,結合 SO_REUSEPORT 與 peering 機制,成功將 PgBouncer 的吞吐量提升了 4 倍,並能處理諸如查詢取消等會話專屬的請求。

標題: 使用 SO_REUSEPORT 與 Peering 將 PgBouncer 吞吐量提升 4 倍

Sources