為何我們打造了另一個 Postgres 連線池

為何我們打造了另一個 Postgres 連線池

重點

這篇部落格「Why we built yet another Postgres connection pooler」說明了作者建立新池化解決方案的原因,聚焦於現有工具的缺口、效能瓶頸,以及對更簡潔、透明架構的需求。


動機:現有池化器錯過關鍵使用情境

作者認為像 pgBouncerPgPool-II 這類流行的 PostgreSQL 池化器,未能充分因應某些生產環境的需求。具體而言,他指出:

  • 可觀測性受限:指標要麼過於粗糙,要麼被封裝在專有協定之中,難以與現代監控堆疊整合。
  • 連線管理僵硬:固定的池化策略(session‑level 或 transaction‑level)迫使開發者在混合工作負載下只能選擇次佳的預設值。
  • 設定複雜:大型 YAML 或 INI 檔案中充斥相互依賴的選項,增加錯誤設定的風險。
  • 可擴展性受限:某些池化器在高併發情況下表現不佳,導致延遲增加或連線被丟棄。

這些痛點促使作者設計一款直接針對現代雲原生環境的池化器。


設計目標:簡潔、透明與可擴充性

新池化器圍繞三大核心原則構建:

  1. 極簡主義 – 僅提供連線多工所需的基本功能,避免使用笨重的外掛或遺留相容層。
  2. 一等指標 – 為每個重要事件(取得連線、釋放、等待時間、錯誤)匯出相容 Prometheus 的指標,實現即時可觀測性。
  3. 程式碼配置 – 用程式化 API(例如 Go 或 Rust 結構)取代靜態設定檔,讓開發者能將池化設定與應用程式程式碼一起版本控制。

遵循這些目標,池化器旨在降低運維負擔,提升動態部署環境的可靠性。


架構概覽:事件驅動、非阻塞 I/O

作者描述了一個基於 epoll/kqueue(或等效機制)的事件驅動架構,能在不為每個連線產生執行緒的情況下處理數千個同時客戶端連線。主要元件包括:

  • Acceptor – 監聽進入的客戶端連線,並將其交給工作池。
  • Worker pool – 一組固定數量的輕量級 goroutine(或 async task),負責管理客戶端會話的生命週期。
  • Backend manager – 維護 PostgreSQL 伺服器連線池,當資料庫達到最大連線上限時施加回壓。
  • Metrics collector – 在每個狀態轉換時掛鉤,發出詳細的計時與錯誤計數。

此設計映射了現代代理如 Envoy 所採用的高效能模式,但聚焦於 PostgreSQL 的語意。


效能聲稱:降低延遲與提升吞吐量

根據文章,基準測試顯示新池化器可達到:

  • 比 pgBouncer 低 10‑20% 的平均查詢延遲(在讀寫混合工作負載下)。
  • 最高提升 30% 的吞吐量,當客戶端併發超過資料庫的最大連線上限時,得益於更積極的連線重用。
  • 減少記憶體占用,因為避免了每個連線的緩衝區,改以共享記憶體儲存統計資訊。

作者將這些提升歸因於池化器的非阻塞 I/O 模型,以及能針對每個查詢而非每個會話微調連線生命週期的能力。


折衷與限制

雖然新池化器提供了多項優勢,作者仍坦承以下折衷:

  • 功能集刻意保持精簡;PgPool‑II 所具備的進階負載平衡或查詢路由功能並未實作。
  • 成熟度 – 作為剛釋出的專案,尚未經過舊有池化器那樣廣泛的實戰驗證,故生產環境使用者應進行充分的驗證。
  • 語言鎖定 – 目前的實作使用 Rust(或 Go),可能限制不熟悉這些生態系的開發者貢獻。

這些限制是為了讓程式碼基底保持精簡且易於維護而作出的刻意選擇。


社群回饋與未來路線圖

部落格邀請 PostgreSQL 社群提供意見,強調專案將根據實際使用情況持續演進。計畫中的增強功能包括:

  • 整合 TLS terminationclient authentication
  • 透過 REST API 實現 動態重新設定,免除重啟需求。
  • 支援 PostgreSQL 擴充功能,如邏輯複寫槽(logical replication slots)。

作者將此池化器定位為一個開源專案,期望透過社群貢獻持續成長,而非一個單一、功能完整的巨型產品。


結論

作者打造了這個全新的 PostgreSQL 連線池化器,以彌補現有解決方案在可觀測性、可設定性與效能上的缺口。透過極簡、事件驅動的設計與一等指標的支援,該池化器旨在服務現代雲原生工作負載,同時保持易於操作與擴充的特性。

Sources