<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Connection-Pooling on Tarragon</title><link>https://tarrragon.github.io/blog/tags/connection-pooling/</link><description>Recent content in Connection-Pooling on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Fri, 22 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/connection-pooling/index.xml" rel="self" type="application/rss+xml"/><item><title>PostgreSQL Connection Pooler Comparison</title><link>https://tarrragon.github.io/blog/backend/01-database/vendors/postgresql/connection-pooler-comparison/</link><pubDate>Fri, 22 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/01-database/vendors/postgresql/connection-pooler-comparison/</guid><description>&lt;p>PostgreSQL connection pooler comparison 的核心責任是把連線數壓力、transaction 語意與維運責任拆開判讀。PostgreSQL backend process 成本高，application instance 擴張後，connection pooler 常成為保護資料庫的第一層容量控制。&lt;/p>
&lt;p>本文的判讀錨點是：pooler 解決的是 connection fan-out 與 queueing，而非查詢本身變快。查詢慢、lock wait、transaction 過長、index 錯誤仍要回到 &lt;a href="../query-optimization/">Query Optimization&lt;/a> 與 &lt;a href="../mvcc-lock-model/">MVCC / lock model&lt;/a>。&lt;/p>
&lt;h2 id="pooling-models">Pooling Models&lt;/h2>
&lt;p>Pooling model 的核心責任是決定 client connection 和 server connection 的綁定時間。PgBouncer 代表最常見的 PostgreSQL pooler 模型；官方文件將 pool mode 分成 session、transaction 與 statement。&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>模式&lt;/th>
 &lt;th>Server connection 綁定&lt;/th>
 &lt;th>適合情境&lt;/th>
 &lt;th>主要風險&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>Session&lt;/td>
 &lt;td>client session 全程&lt;/td>
 &lt;td>使用 session state、temp table&lt;/td>
 &lt;td>壓縮率低&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Transaction&lt;/td>
 &lt;td>transaction 期間&lt;/td>
 &lt;td>Web API、短交易、Stateless query&lt;/td>
 &lt;td>session variable、prepared statement 語意受限&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Statement&lt;/td>
 &lt;td>single statement&lt;/td>
 &lt;td>特殊 read-only workload&lt;/td>
 &lt;td>transaction workflow 受限&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>App pool&lt;/td>
 &lt;td>application process 內&lt;/td>
 &lt;td>單服務、低 fan-out&lt;/td>
 &lt;td>多 instance 後總連線失控&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/transaction-pooling/" data-link-title="Transaction Pooling" data-link-desc="說明 connection pooler 的 transaction 綁定模式如何壓縮連線並改變 session 語意">Transaction pooling&lt;/a> 的價值在於把大量 idle client connection 收斂成少量 active server connection。它要求 application 把 session state 放回 request / transaction boundary，例如 timezone、role、search_path、prepared statement 與 advisory lock 都要明確管理。&lt;/p>
&lt;p>Session pooling 的價值在於相容性。若 application 大量使用 temp table、LISTEN / NOTIFY、session-level setting 或 server-side prepared statement，session pooling 能降低行為差異，但連線壓縮效果較弱。&lt;/p>
&lt;h2 id="product-boundary">Product Boundary&lt;/h2>
&lt;p>Product boundary 的核心責任是把 pooler 放在正確的維運位置。不同選項的責任邊界差異很大。&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>選項&lt;/th>
 &lt;th>主要責任&lt;/th>
 &lt;th>適合情境&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>PgBouncer&lt;/td>
 &lt;td>輕量 PostgreSQL connection pooling&lt;/td>
 &lt;td>自管 VM / K8s、transaction pooling 標準路線&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Odyssey&lt;/td>
 &lt;td>多租戶與複雜 routing pooler&lt;/td>
 &lt;td>大型部署、需要進階 routing / auth&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>RDS Proxy&lt;/td>
 &lt;td>AWS managed connection proxy&lt;/td>
 &lt;td>RDS / Aurora 生態、希望降低 proxy 維運&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Application pool&lt;/td>
 &lt;td>服務內部連線池&lt;/td>
 &lt;td>instance 數少、連線總量可控&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>No pooler&lt;/td>
 &lt;td>直接連 PostgreSQL&lt;/td>
 &lt;td>小型服務、低併發、連線數遠低於上限&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>PgBouncer 的操作重點是 mode、pool size、server reset query、auth、TLS 與 metrics。它很適合放在 application 與 database 中間，承擔連線排隊與 backpressure。&lt;/p></description><content:encoded><![CDATA[<p>PostgreSQL connection pooler comparison 的核心責任是把連線數壓力、transaction 語意與維運責任拆開判讀。PostgreSQL backend process 成本高，application instance 擴張後，connection pooler 常成為保護資料庫的第一層容量控制。</p>
<p>本文的判讀錨點是：pooler 解決的是 connection fan-out 與 queueing，而非查詢本身變快。查詢慢、lock wait、transaction 過長、index 錯誤仍要回到 <a href="../query-optimization/">Query Optimization</a> 與 <a href="../mvcc-lock-model/">MVCC / lock model</a>。</p>
<h2 id="pooling-models">Pooling Models</h2>
<p>Pooling model 的核心責任是決定 client connection 和 server connection 的綁定時間。PgBouncer 代表最常見的 PostgreSQL pooler 模型；官方文件將 pool mode 分成 session、transaction 與 statement。</p>
<table>
  <thead>
      <tr>
          <th>模式</th>
          <th>Server connection 綁定</th>
          <th>適合情境</th>
          <th>主要風險</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Session</td>
          <td>client session 全程</td>
          <td>使用 session state、temp table</td>
          <td>壓縮率低</td>
      </tr>
      <tr>
          <td>Transaction</td>
          <td>transaction 期間</td>
          <td>Web API、短交易、Stateless query</td>
          <td>session variable、prepared statement 語意受限</td>
      </tr>
      <tr>
          <td>Statement</td>
          <td>single statement</td>
          <td>特殊 read-only workload</td>
          <td>transaction workflow 受限</td>
      </tr>
      <tr>
          <td>App pool</td>
          <td>application process 內</td>
          <td>單服務、低 fan-out</td>
          <td>多 instance 後總連線失控</td>
      </tr>
  </tbody>
</table>
<p><a href="/blog/backend/knowledge-cards/transaction-pooling/" data-link-title="Transaction Pooling" data-link-desc="說明 connection pooler 的 transaction 綁定模式如何壓縮連線並改變 session 語意">Transaction pooling</a> 的價值在於把大量 idle client connection 收斂成少量 active server connection。它要求 application 把 session state 放回 request / transaction boundary，例如 timezone、role、search_path、prepared statement 與 advisory lock 都要明確管理。</p>
<p>Session pooling 的價值在於相容性。若 application 大量使用 temp table、LISTEN / NOTIFY、session-level setting 或 server-side prepared statement，session pooling 能降低行為差異，但連線壓縮效果較弱。</p>
<h2 id="product-boundary">Product Boundary</h2>
<p>Product boundary 的核心責任是把 pooler 放在正確的維運位置。不同選項的責任邊界差異很大。</p>
<table>
  <thead>
      <tr>
          <th>選項</th>
          <th>主要責任</th>
          <th>適合情境</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>PgBouncer</td>
          <td>輕量 PostgreSQL connection pooling</td>
          <td>自管 VM / K8s、transaction pooling 標準路線</td>
      </tr>
      <tr>
          <td>Odyssey</td>
          <td>多租戶與複雜 routing pooler</td>
          <td>大型部署、需要進階 routing / auth</td>
      </tr>
      <tr>
          <td>RDS Proxy</td>
          <td>AWS managed connection proxy</td>
          <td>RDS / Aurora 生態、希望降低 proxy 維運</td>
      </tr>
      <tr>
          <td>Application pool</td>
          <td>服務內部連線池</td>
          <td>instance 數少、連線總量可控</td>
      </tr>
      <tr>
          <td>No pooler</td>
          <td>直接連 PostgreSQL</td>
          <td>小型服務、低併發、連線數遠低於上限</td>
      </tr>
  </tbody>
</table>
<p>PgBouncer 的操作重點是 mode、pool size、server reset query、auth、TLS 與 metrics。它很適合放在 application 與 database 中間，承擔連線排隊與 backpressure。</p>
<p>Managed proxy 的操作重點是平台限制、failover behavior、credential integration、latency overhead 與 observability。若 team 想少維護一個 pooler process，managed proxy 可以降低操作成本，但要接受雲平台邊界。</p>
<h2 id="decision-signals">Decision Signals</h2>
<p>Decision signals 的核心責任是判斷何時導入 pooler，以及導入哪一種。連線數壓力要用 evidence 說明。</p>
<table>
  <thead>
      <tr>
          <th>訊號</th>
          <th>代表問題</th>
          <th>建議路由</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>max_connections</code> 接近上限</td>
          <td>application fan-out 過高</td>
          <td>PgBouncer transaction pooling</td>
      </tr>
      <tr>
          <td>大量 idle connection</td>
          <td>client 連線長期閒置</td>
          <td>transaction pooling 或 app pool 調整</td>
      </tr>
      <tr>
          <td>failover 後 reconnect storm</td>
          <td>client 同時重連衝擊 primary</td>
          <td>pooler queue + jitter</td>
      </tr>
      <tr>
          <td>query latency 高但 connection 不高</td>
          <td>查詢 / lock / index 問題</td>
          <td>query optimization</td>
      </tr>
      <tr>
          <td>session state 依賴多</td>
          <td>transaction pooling 相容性風險</td>
          <td>session pooling 或 refactor session state</td>
      </tr>
  </tbody>
</table>
<p>Connection pooler 的成功訊號是 database backend count 下降、queue 可觀測、error rate 穩定、tail latency 受控。若導入後只是把 timeout 從 DB 移到 pooler，代表 capacity model 仍需調整。</p>
<h2 id="transaction-pooling-compatibility">Transaction Pooling Compatibility</h2>
<p>Transaction pooling compatibility 的核心責任是找出 application 對 session state 的隱性依賴。這些依賴要在 staging 先測出來。</p>
<table>
  <thead>
      <tr>
          <th>依賴類型</th>
          <th>風險</th>
          <th>修正策略</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>SET search_path</code></td>
          <td>下一個 transaction 可能換連線</td>
          <td>每個 transaction 明確設定或固定 schema</td>
      </tr>
      <tr>
          <td>temp table</td>
          <td>transaction 後 server connection 釋放</td>
          <td>改 permanent staging table 或 session mode</td>
      </tr>
      <tr>
          <td>prepared statement</td>
          <td>server-side state 不穩定</td>
          <td>使用 client-side prepare 或 session mode</td>
      </tr>
      <tr>
          <td>advisory lock</td>
          <td>lock ownership 混亂</td>
          <td>transaction-scoped lock 或移出 pooler path</td>
      </tr>
      <tr>
          <td>LISTEN / NOTIFY</td>
          <td>session channel 需要持續連線</td>
          <td>專用 direct connection</td>
      </tr>
  </tbody>
</table>
<p>Compatibility review 要在 repository / migration / background job 三個層面跑。Web request 通常容易改成 transaction-safe；migration tool、CDC job、worker queue 常有長連線與 session state，要分開配置。</p>
<h2 id="sizing-and-evidence">Sizing and Evidence</h2>
<p>Sizing and evidence 的核心責任是用 workload 設定 pool size。Pooler 設太大會把壓力直接傳到 PostgreSQL；設太小會造成 queue 與 timeout。</p>
<p>基本 sizing 步驟：</p>
<ol>
<li>量測 active query concurrency，而非只看 request concurrency。</li>
<li>設定 database 保留連線給 admin、replication、migration 與 emergency access。</li>
<li>每個 service 設定 pool quota，避免單一服務吃掉全部 backend。</li>
<li>觀測 wait time、server utilization、client timeout、query latency。</li>
<li>用 load test 驗證 failover / reconnect storm。</li>
</ol>
<p>Pooler dashboard 至少要有 client connections、server connections、waiting clients、pool wait time、server reuse、timeout count 與 authentication failure。</p>
<h2 id="anti-patterns">Anti-Patterns</h2>
<p>Anti-pattern 的核心責任是把 pooler 常見誤用提前排除。</p>
<table>
  <thead>
      <tr>
          <th>反模式</th>
          <th>風險</th>
          <th>修正方向</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>把 pool size 設到 DB 上限</td>
          <td>DB 失去保護層</td>
          <td>每個服務配額 + 保留 admin capacity</td>
      </tr>
      <tr>
          <td>transaction pooling 直接上線</td>
          <td>session state 依賴在 production 爆出</td>
          <td>staging compatibility matrix</td>
      </tr>
      <tr>
          <td>pooler 沒有 metrics</td>
          <td>queueing 事故難以判讀</td>
          <td>pooler dashboard + alert</td>
      </tr>
      <tr>
          <td>migration 共用 web pool</td>
          <td>長 DDL 卡住 web request</td>
          <td>migration 專用連線與維護窗口</td>
      </tr>
      <tr>
          <td>retry 無 jitter</td>
          <td>reconnect storm 放大</td>
          <td>exponential backoff + jitter</td>
      </tr>
  </tbody>
</table>
<p>Pooler 是 backpressure 元件。它要讓系統在過載時可排隊、可拒絕、可觀測，而非把所有請求推進 database。</p>
<h2 id="下一步路由">下一步路由</h2>
<p>Connection pooler comparison 完成後，實作層讀 <a href="../pgbouncer-config/">PgBouncer config</a>；要觀察連線壓力讀 <a href="../connection-scaling/">Connection Scaling</a>；需要演練讀 <a href="../hands-on/connection-pool-lab/">Connection Pool Lab</a>。</p>
]]></content:encoded></item></channel></rss>