Hacker News 中文摘要

RSS订阅

我们为何又构建了一个Postgres连接池 -- Why we built yet another Postgres connection pooler

文章摘要

这篇文章介绍了为何开发新的PostgreSQL连接池工具PgDog。现有工具如PgBouncer存在抽象漏洞,部署后需修改应用代码。PgDog无需改变代码即可实现连接池功能,解决了会话控制等连接状态问题。

文章总结

好的,这是根据您的要求,对原文进行的中文重述,保留了核心细节,并删减了与主题无关的评论性内容。


标题:我们为什么又造了一个Postgres连接池

核心内容:

PgDog是一个用于扩展Postgres的代理,其核心功能之一是连接池,允许多个客户端应用共享同一个数据库而不会超出其连接限制。尽管市面上已有PgBouncer、RDS Proxy、Pgpool-II、Supavisor等多种连接池工具,我们仍决定构建PgDog,主要基于以下原因:

  1. 解决“有漏洞的抽象”问题:许多现有工具(如PgBouncer)遵循“单一职责”的Unix哲学,但引入了一种“有漏洞的抽象”。部署它们后,用户会意识到这改变了数据库的使用方式,需要做出权衡,甚至修改应用代码。对于已运行一段时间的应用,这可能意味着修改数千行缺乏测试覆盖的生产代码。PgDog旨在消除这种必要性。

  2. 处理连接状态(SET语句):传统连接池会复用客户端连接,导致一个客户端的连接状态(如通过SET语句设置的参数)“泄漏”给另一个客户端,可能引发严重问题(如慢查询或行级安全策略失效)。因此,迁移到连接池时通常建议放弃使用SET。但SET是Postgres的实用功能。PgDog内置了SQL解析器,能检测SET语句,提取变量并存储在每个客户端连接上。当客户端执行查询时,PgDog会检查其状态是否与服务器匹配,若不匹配,则自动执行一系列SET语句进行更新。该算法效率很高,即使多个变量不同,也能通过查询流水线在一个往返中完成更新,从而在扩展时仍能使用SET功能。

  3. 支持LISTEN/NOTIFYLISTENNOTIFY是Postgres内置的发布/订阅功能。在使用事务模式的连接池时,这个功能通常需要放弃。PgDog在内部处理这两个命令,并在多个PgDog进程间传递消息。对客户端而言,PgDog看起来像消息代理,但实际后端仍是Postgres。PgDog保留了NOTIFY的事务语义,并修复了可能导致数据库故障的问题。其内部实现利用了Tokio的广播通道在同一进程内传递消息,并通过专用连接将LISTENNOTIFY命令发送给Postgres,使PgDog充当一个代理其他发布/订阅客户端的发布/订阅客户端。

  4. 多线程架构:PgDog基于Tokio(一个Rust异步运行时)构建,采用多线程工作模式。每个客户端由独立的异步任务处理,连接数增加时性能线性扩展。这允许单个PgDog进程利用多核CPU服务更多客户端和查询。相比之下,PgBouncer和RDS Proxy等工具需要“分片”连接池,每个代理进程有专属的Postgres连接,客户端一旦连接便无法切换实例,可能导致过载。PgDog的多线程进程能处理更大流量,用更少的服务器连接池化更多客户端,提高连接利用率和效率,并能更好地应对突发查询,无需等待自动扩展,从而满足延迟SLA要求。此外,管理多线程进程的运维手册更简洁,指标和健康检查来源单一,避免了将复杂性推入难以调试的层面。

总结:

尽管替换像PgBouncer这样有20年历史的项目颇具挑战,但PgDog通过解决上述问题,提供了一个更优的选择。它已在生产环境中运行超过一年,以每秒200万次查询的速度进行连接池化。PgDog是开源且免费的,可部署在任何地方。

评论总结

根据评论内容,主要观点和论据如下:

1. 连接池化带来的实际问题(评分:无) - 用户mmakeev指出,将Django应用迁移到pgbouncer事务池后,queryset.iterator()依赖的服务器端游标无法在池化环境中存活,需回退到客户端游标;同时statement_timeout需从应用连接选项移至池化器的连接查询中。 - 关键引用:"we had to disable it everywhere and let it fall back to client side" / "had to move statement_timeout out of the app's connection options into the pooler's own connect query"

2. 连接状态泄漏的担忧(评分:无) - 用户petters对连接池复用导致状态泄漏表示惊讶,质疑这是否是典型Postgres设置中的常见问题。 - 关键引用:"Wow this is very bad. This actually happens in typical Postgres setups?" / "the connection state of one client 'leaks' into the connection state of another"

3. 性能与功能改进(评分:无) - 用户jauntywundrkind提及Clickhouse关于扩展pgbouncer的文章,讨论通过so_reuseport扩展而不需严格分片(pgdog通过重写解决此限制)。 - 用户inigyou质疑NOTIFY性能修复是否破坏了事务性。 - 用户khurs询问是否计划添加SELECT查询缓存(参考pgpool的内存查询缓存)。 - 用户babayega2询问是否有处理PostgreSQL模式切换的池化器(如Django-tenant前端)。

4. 许可证评价(评分:无) - 用户27183赞赏AGPL许可证,认为其优于BSL变体。 - 关键引用:"It's awesome to see AGPL instead of the horrible BSL variants" / "that have been going around"

总结:评论主要围绕连接池化带来的实际挑战(如游标失效、状态泄漏)、功能改进需求(查询缓存、模式切换)以及许可证选择。用户对AGPL表示积极认可,同时指出池化环境中的配置迁移和事务性问题。