PgCat 命名预编译语句:让 Postgres 生产吞吐量提升 30% 的连接池预编译缓存实现
发布时间:2026/10/8 1:36:11 作者:尧图编辑部 阅读量:1,286

后端人工智能机器学习RAG向量数据库【免费下载链接】postgresmlPostgres with GPUs for ML/AI apps.项目地址https://gitcode.com/gh_mirrors/po/postgresml点击查看免费下载导读在生产环境中运行 Postgres几乎必然要在“连接池复用”与“预编译语句prepared statements”之间做取舍经典方案是用 PgBouncer 的 transaction 模式共享服务端连接代价是放弃查询计划缓存带来的性能收益。PostgresML 开源的连接池与代理 PgCat 自 PR #474 起打破了这一成规在会话与事务模式下同时支持 prepared statements通过内部缓存与全局唯一命名让客户端既能复用连接、又能享受查询计划缓存。读完本文你将理解 PgCat 的预编译语句缓存实现原理、pgbench基准的实验设计、prepare_cache_hit/prepare_cache_miss监控指标以及如何用pgcat.toml一键开启这一能力。性能权衡共享连接与查询计划缓存为何不可兼得任何以规模方式运行 Postgres 的人都清楚性能总是伴随着取舍。经典部署剧本是在数据库前放置一个连接池如 PgBouncer并开启事务模式transaction mode让多个客户端复用同一条服务端连接从而允许数千客户端同时连接数据库而不会触发“fork bomb”式的进程爆炸。这条路的代价是由于多个客户端共享同一条服务端连接它们无法再使用预编译语句prepared statements。预编译语句是 Postgres 提供的一种机制——缓存一条查询的执行计划query plan之后用不同参数反复执行。如果你还没有尝试过可以在本地数据库上跑一次pgbench会看到--protocol prepared比simple和extended协议至少快 30%。放弃这一特性在很长一段时间里被视为生产部署的既定代价但如今已不再如此。PgCat 的预编译语句支持自 PgCat PR #474 起PgCat 在会话模式session mode和事务模式transaction mode下都支持 prepared statements。项目初始基准显示相比 extended 协议--protocol extended提升 30%相比 simple 协议--simple提升 15%。大多数全部Web 框架至少会使用 extended 协议因此这意味着所有写 Web 应用、在生产环境使用 Postgres 的团队只需切换到命名预编译语句named prepared statements就能普遍获得约 30% 的性能提升。对 Rails 应用来说启用它简单到只需设置prepared_statements: true这不仅是性能收益也是可用性改善——尤其对必须使用 prepared statements 的客户端库如流行的 Rust 数据库 crate SQLx而言。在此之前对这类客户端的典型建议是“干脆别用连接池”。Benchmark实验设置与结果基准使用pgbench进行客户端数量分别为 1、10、100 和 1000向 PgCat 发送了数百万条查询。PgCat 本身运行在与数据库不同的另一台 EC2 机器上这是生产环境常见的一种简单部署形态另一种形态是让连接池独占一台机器——这会增加一点延迟但提升可用性。客户端则部署在第三台 EC2 机器上以模拟 Kubernetes、ECS、EC2 等典型 Web 应用部署中实际会遇到的网络延迟。基准在事务模式下运行。会话模式在客户端数量较少时更快但在生产环境中一旦客户端超过几百个就无法扩展。基准只使用了SELECT语句-S选项因为典型pgbench基准的写读比例与实际生产负载并不相符——大多数应用 90% 的时间在读取、10% 的时间在写入而预编译语句恰恰在读取场景最能体现价值。pgbench 基准simple、extended 与 prepared 三种协议在不同并发客户端下的吞吐量对比.png)从基准结果纵轴为每秒查询数横轴为客户端数可以看出低并发1 个客户端时三种协议性能相近随着并发提升prepared 模式的吞吐量优势逐步拉大在 100 客户端附近达到峰值即便在 1000 客户端的高并发下仍显著高于 simple 与 extended 模式。ImplementationPgCat 的预编译语句缓存机制PgCat 在内部实现了一个缓存与映射将客户端的 prepared statements 与服务器上可能存在的也可能不存在的prepared statements 对应起来缓存命中如果服务器上已经存在该预编译语句PgCat 直接转发Bind (F)、Execute (F)和Describe (F)消息不做额外处理。缓存未命中如果服务器上还没有该语句PgCat 从客户端缓存中取出语句用Parse (F)消息在服务器上完成预编译再继续后续流程。这一机制对应 Postgres 扩展协议extended protocol的消息流核心思路是让连接池扮演“翻译官”的角色把客户端的预编译请求映射到正确的服务端连接上。一个关键实现细节是PgCat 中所有预编译语句都会被重命名并赋予全局唯一名称。这意味着那些不随机化预编译语句名、并期望“断开与 Postgres 服务器的连接后语句就消失”的客户端可以按预期工作这里的“Postgres 服务器”加了引号因为客户端实际连接的是一台伪装成 Postgres 数据库的代理。使用这类客户端配合 PgBouncer 时的典型报错是prepared statement sqlx_s_2 already exists第一次见到这个错误时往往令人困惑而 PgCat 的全局唯一重命名正是为了消除这类问题。Metrics缓存命中与未命中监控PgCat 在管理数据库admin database中新增了两个指标prepare_cache_hit与prepare_cache_miss。prepare_cache_hit缓存命中客户端请求的预编译语句在服务器上已经存在。这是好事因为 PgCat 只需改写消息并立即转发给服务器。prepare_cache_miss缓存未命中PgCat 不得不向服务器发起一次预编译调用这会消耗额外时间并降低吞吐量。理想情况下命中次数应比未命中次数高出一个数量级如果两者持平甚至未命中更多说明客户端的预编译语句使用方式不正确。SHOW SERVERS 输出中的 prepare_cache_hit 与 prepare_cache_miss 指标.png)项目的基准测试实现了 99.99% 的缓存命中率这非常理想但生产环境中的这一数字大概率会更低。你可以通过管理数据库执行SHOW SERVERS来监控命中/未命中比例如上图所示——每个服务器条目都会带出prepare_cache_hit与prepare_cache_miss两列计数。配置用 pgcat.toml 一键开启该特性是可选的并且可以在不重启 PgCat 的情况下动态启用或禁用。在pgcat.toml中开启只需[general] prepared_statements true对应的完整配置说明参见仓库中的 PgCat 配置文档。几个与预编译语句直接相关的要点prepared_statements在事务与会话模式下启用/禁用 prepared statements 支持。预编译语句是缓存起来的 SQL 查询可搭配不同参数复用能显著提升生产环境中SELECT查询的性能。默认值false禁用。prepared_statements_cache_size连接池为同一客户端保留的预编译语句数量。该值越高缓存命中机会越大越不需要重复预编译同一 SQL但该值并非无限因为保留预编译语句会占用 PgCat 内存与 Postgres 服务器资源。默认值500。pool_mode在[pools]段transaction模式让多个客户端共享服务端连接、提高并发度session模式则为每个客户端独占一条服务端连接。默认值transaction。一个可运行的最小配置示例单主、无分片如下详见 configuration.md[general] port 6432 admin_username pgcat admin_password my-pony-likes-to-dance-tango [pools.my_database] [pools.my_database.users.0] pool_size 5 username developer password very-secure-password [pools.my_database.shards.0] database postgresml servers [ [127.0.0.1, 5432, primary], ]配置完成后用psql连接时注意连接串中的数据库名使用的是池名my_database而不是 Postgres 中真实的数据库名psql postgres://developer:very-secure-password127.0.0.1:6432/my_database从部署形态看PgCat 是 PostgresML 生产基础设施的一部分在仓库的 RDS 代理部署脚本 中PgCat 被按架构amd64/arm64从官方静态包地址下载并安装到/usr/local/bin/pgcat作为 RDS 实例前的代理使用。自行部署时也可以参考 安装文档 选择从源码编译cargo build --release、Ubuntu 22.04 的 Apt 源安装或 Docker 挂载pgcat.toml运行。Roadmap 与已知限制实现本身相当简洁收益已经非常可观但仍可做得更好。当前的已知边界包括显式PREPARE语句通过Parse (F)消息建立的预编译语句可以正常工作但如果客户端用PREPARE显式预编译语句PgCat 目前会忽略它这类查询在会话模式之外很可能无法工作。DEALLOCATE与DISCARDPgCat 目前不会拦截这两类调用客户端有可能在 PgCat 不知情的情况下破坏服务端预编译语句缓存。拦截并对这类查询采取相应动作是容易修复的但尚未实现。基准与生产的差异pgbench是人工基准好处是控制变量后能公平对比不同实现与配置的优劣坏处是真实世界的负载可能带来不同结果。作者也在寻找愿意用生产流量验证实现效果的用户并欢迎反馈。该特性可动态启停——修改pgcat.toml中的prepared_statements开关配合autoreload配置或手动重载即可生效无需重启连接池。对于既想保留连接池的高并发连接复用、又不想放弃预编译语句性能收益的 Postgres 生产用户而言这正是 PgCat 给出的新答案。赞分享后端人工智能机器学习RAG向量数据库【免费下载链接】postgresmlPostgres with GPUs for ML/AI apps.项目地址https://gitcode.com/gh_mirrors/po/postgresml点击查看免费下载相关推荐Finagle MySQL 客户端核心指标全解析连接池回滚、游标流与预编译语句缓存Finagle MySQL 客户端核心指标全解析连接池回滚、游标流与预编译语句缓存 导读 本文聚焦 Finagle 的 MySQL 客户端 com.twit后端RPC框架PostgreSQL 命名语句实战使用 PREPARE、EXECUTE 与 DEALLOCATE 管理预编译语句PostgreSQL 命名语句实战使用 PREPARE、EXECUTE 与 DEALLOCATE 管理预编译语句 导读 在 PostgreSQL 中除了即时文档教程知识库LunaTV IPTV 接入教程三步配好 M3U 订阅变成分组频道列表LunaTV IPTV 接入教程三步配好 M3U 订阅变成分组频道列表 LunaTV 的直播模块能把一条 M3U 订阅地址解析成按分组整理的频道列表并自动前端后端音视频上一篇Reactjs-popup菜单组件深度解析构建现代化下拉菜单和上下文菜单下一篇ComfyUI-WanVideoWrapper与Blender集成3D场景与视频生成工作流创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考