PgCat:用 Rust 重写的 PostgreSQL 连接池,比 PgBouncer 多了路由与故障转移
阅读时间: 大约 13 分钟
PgCat:用 Rust 重写的 PostgreSQL 连接池,比 PgBouncer 多了路由与故障转移

PgCat 是 PostgresML 团队用 Rust 编写的 PostgreSQL 连接池与代理(pooler/proxy),自我定位为”like PgBouncer”但额外支持分片、负载均衡、故障转移与镜像。项目采用 MIT 协议,调研时约 4.0k star、267 fork,运行在 Tokio 异步运行时上。官方称其已在生产环境”serve hundreds of thousands of queries per second”,落地用户包括 Instacart、PostgresML、OneSignal。本文回到官方 GitHub README,区分 Stable 与 Experimental,核验它相对 PgBouncer 真正多出来的能力,以及官方没有承诺的部分。
一、背景动机:PostgreSQL 连接模型的天然瓶颈
PostgreSQL 每个后端连接都是一个独立操作系统进程,各自占用内存。成百上千个大多空闲的应用连接会把数据库资源耗在维护进程上,而不是回答查询。连接池的本质,是把大量短寿命客户端连接复用到一组数量可控、稳定的服务器连接上,让数据库在突发流量下保持可预测。PgBouncer 是这个领域的事实标准,但其单进程模型与长期存在的”异常客户端/废弃事务”处理问题,给了 PgCat 切入空间。
二、两种池化模式:会话池与事务池(Stable)
PgCat 完整提供 PgBouncer 的两种模式,默认开启事务池:
- Session mode(会话池,
pool_mode = "session"):一个客户端在整条连接生命周期内独占一台服务器。支持预处理语句(prepared statements)、SET、咨询锁(advisory locks),能力上与直连服务器几乎无差别; - Transaction mode(事务池,默认):客户端只在单个事务期间占用服务器,事务结束即归还连接池。官方明确:此模式下不支持预处理语句、
SET、咨询锁,替代方案是作用域限于事务的SET LOCAL与pg_advisory_xact_lock。
三、超过传统连接池的四项能力
3.1 多线程运行时(Stable)
PgBouncer 经典上是单进程/协作式模型,PgCat 基于 Tokio 异步运行时,单个进程可利用多核;官方示例部署默认拉起 4 个 worker,建议配 4 颗 CPU,worker 数量可调。
3.2 读查询负载均衡(Stable)
内置查询解析器(sqlparser crate)尽量把 SELECT 路由到副本,把写操作与显式事务路由到主库;读请求在配置的服务器间用 random 或 least open connections(最少开放连接)算法负载均衡。解析器拿不准时,客户端可用扩展 SQL 自己指定:
SET SERVER ROLE TO 'primary'; -- 下一事务走主库
SET SERVER ROLE TO 'replica'; -- 下一事务走副本
SET SERVER ROLE TO 'auto'; -- 交解析器决定
SET SERVER ROLE TO 'any'; -- 随机挑一台
SET SERVER ROLE TO 'default'; -- 恢复默认该设置持续到再次修改或客户端断开;默认行为由 default_role 控制。
3.3 故障转移(Stable)
每台服务器在交给客户端之前先用一个极快的 ; 查询做健康检查,日常也随每个客户端查询持续探测。不可达服务器被**封禁(ban)**一段时间(ban_time 默认 60 秒),期间不再服务,流量改道剩余健康节点;官方特别说明:若所有服务器都被封禁,会清空封禁列表作为误报(false positive)的安全兜底;主库永远不会被封禁。
3.4 热更新与可观测(Stable)
除 host、port 外,所有配置(含分片与副本配置)都可通过给进程发 SIGHUP,或向管理库执行 RELOAD 动态重载,无需重启。管理上提供兼容 PgBouncer 的 pgbouncer 与 pgcat 两个管理库(沿用熟悉的 SHOW 命令),并通过 HTTP 端点 /metrics 暴露 Prometheus 指标。传输层支持客户端与池之间、池与服务器之间双向 TLS;客户端用 MD5 认证,池连服务端支持 MD5 与 SCRAM-SHA-256;还可用 auth_query 做认证透传,配置文件不落明文密码。
3.5 实验性能力(Experimental,勿用于关键路径)
- 分片:扩展语法
SET SHARD TO '1'指定分片、SET SHARDING KEY TO '1234'让池按值选片;也可在 SQL 注释里携带分片键(配合 ActiveRecord/SQLAlchemy annotate),或由池自动解析查询识别分片键;哈希采用与 PostgreSQL 声明式分区一致的PARTITION BY HASH; - 镜像(Mirroring):把同一条查询同时发给多个数据库,用于把副本预热到可上线,或用真实生产流量测试不同 PostgreSQL 版本。
四、功能状态矩阵(官方 README)
| 功能 | 官方状态 | 备注 |
|---|---|---|
| 事务池 | Stable | 与 PgBouncer 一致,并改进了异常客户端与废弃事务处理 |
| 会话池 | Stable | 与 PgBouncer 一致 |
| 多线程运行时 | Stable | Tokio,利用多核 |
| 读查询负载均衡 | Stable | 自动在副本与主库间均衡 |
| 故障转移 | Stable | 定期健康检查,自动绕开坏副本 |
| 管理库统计 | Stable | pgbouncer/pgcat 管理库 |
| Prometheus 指标 | Stable | HTTP 端点 |
| SSL/TLS | Stable | 客户端与服务器双向 TLS |
| 客户端/服务端认证 | Stable | 客户端 MD5;服务端 MD5 + SCRAM-SHA-256 |
| 配置热更新 | Stable | host/port 除外 |
| 认证透传 | Stable | auth_query,无需明文密码 |
| 扩展语法分片 | Experimental | 客户端动态指定分片 |
| 注释/正则分片 | Experimental | 查询注释携带分片键 |
| 自动分片 | Experimental | 解析查询自动识别分片键 |
| 镜像 | Experimental | 多库同时路由以预演/压测 |
五、口径与局限:官方没有承诺的部分
- “数十万 QPS”是项目方自述的生产规模,非独立基准:README 未发布标准化压测,自测仅要求用 pgbench(simple/extended 两种协议)回归协议改动,没有公开的时延、p99 或对比 PgBouncer 的吞吐数字;不能把这句话当成可复现的性能承诺。
- 查询解析器是 best-effort:官方明说”解析器会尽力判断去向,但有时做不到”,误判时需客户端用
SET SERVER ROLE纠正;复杂语句、自定义函数、非标准写法都可能让路由决策落空。 - 分片与镜像仍是 Experimental:自动分片依赖 SQL 解析,注释/正则方式侵入查询,生产分片仍建议自行校验路由正确性。
- 事务池的语义约束不可忽略:预处理语句、
SET、咨询锁在事务池不可用,迁移现有应用时这类用法需要改写成SET LOCAL/ xact 锁,否则会出现跨事务状态串味。 - 故障转移是连接层绕行,不是 PostgreSQL 原生高可用:它封禁的是”连不上的副本”,主库永不封禁,本身不实现主从提升(failover promotion),数据库层的选主仍要靠 Patroni/repmgr 等方案。
- 封禁全清策略是双刃剑:所有节点被封时清空列表以防误报,极端故障下可能瞬间把流量打给其实不健康的节点。
六、适用与不适用场景
适合:
- 已有一主多从、希望在连接层做读写分离与读负载均衡,而不想让应用自己判断路由的团队;
- 需要从 PgBouncer 平滑迁移、兼容
SHOW管理命令与配置习惯,同时想要多核与热更新的团队; - 需要健康检查自动绕开坏副本、用 Prometheus 观测连接池的生产服务;
- 想用镜像功能拿真实流量预热副本或测试大版本升级。
不适合:
- 只想要最简单单机连接池、无副本、无路由需求(PgBouncer 更轻更成熟);
- 把 Experimental 分片/镜像当正式分布式分片方案;
- 依赖事务池里的预处理语句/会话级
SET/咨询锁而不愿改造的应用; - 期待 PgCat 完成主库自动选主与容灾切换的场景。
七、客观分析:优势与局限
优势:
- PgBouncer 兼容 + 增量能力:两种池化模式与管理命令延续习惯,迁移成本低,又补上了读均衡、故障转移、热更新;
- Rust/Tokio 多核模型,相比单进程池更能吃满机器,且内存安全;
- 路由决策内建,应用无需集成读写分离 SDK,扩展 SQL 给了手动兜底手段;
- 观测与运维齐全:Prometheus、双管理库、双向 TLS、auth_query;
- MIT 协议、有 Instacart 等生产用户背书。
局限:
- 无公开独立基准,性能优势主要来自多核模型而非可量化跑分;
- 解析路由不保证正确,关键写路径仍需显式指定;
- 分片/镜像未成熟,距离”数据库中间件”还有差距;
- 不替代数据库高可用组件,定位是池+代理,不是选主系统;
- 生态与文档沉淀时间短于 PgBouncer,疑难问题的社区资料相对少。
八、它意味着什么
PgCat 证明连接池正在从”单纯复用连接”演进为”带路由与高可用的轻量代理”。对一主多从、读写分离是刚需的 PostgreSQL 团队,它提供了一条兼容 PgBouncer 的低风险升级路径;但它的护城河是连接层治理,不是性能神话,更不是分片或容灾的全部答案。生产采用前应自行用 pgbench 与真实 SQL 校验解析路由,并把 Experimental 功能隔离在非关键路径。