将 PgBouncer 吞吐量提升 4 倍:使用 SO_REUSEPORT 与 Peering
将 PgBouncer 吞吐量提升 4 倍:使用 SO_REUSEPORT 与 Peering
ClickHouse 将 PgBouncer 吞吐量提升 4 倍
ClickHouse 通过在单台机器上运行多个 PgBouncer 进程,将 PgBouncer 的吞吐量提升了 4 倍。这种做法克服了 PgBouncer 单线程的特性——通常只能利用单个 CPU 核心的性能——通过使用 SO_REUSEPORT 套接字选项,将连接负载分配到多个进程上。
使用 SO_REUSEPORT 进行负载分配
为了实现高吞吐量,ClickHouse 使用了 SO_REUSEPORT。该套接字选项允许多个进程绑定同一个 IP 地址和端口。Linux 内核随后会以轮询或哈希方式将进入的 TCP 连接分配给这些进程。这实际上把单个 PgBouncer 实例转变为多进程架构,使系统能够随分配给进程池的 CPU 核心数量线性扩展。
通过 Peering 解决查询取消问题
虽然 SO_REUSEPORT 能分配连接,但它也带来了一个挑战:查询取消请求可能落在并不拥有该会话的 PgBouncer 进程上。由于标准的 PgBouncer 架构是相互隔离的,收到不认识的会话的取消请求的进程通常会直接忽略,导致查询取消失败。
为了解决此问题,ClickHouse 实现了 peering 机制。Peering 使 PgBouncer 进程之间能够相互通信。当进程收到一个它不拥有的会话的取消请求时,会将该请求转发给实际管理该会话的同伴进程。这样即可保证查询取消在分布式进程池中仍然有效。
实现与配置
根据社区讨论,此方案的配置需要启用 so_reuseport 并定义 peer ID 及其对应的套接字。示例配置结构如下:
[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 6432
so_reuseport = 1
peer_id = 1
unix_socket_dir = /tmp/pgbouncer1
[peers]
1 = host=/tmp/pgbouncer1
2 = host=/tmp/pgbouncer2
3 = host=/tmp/pgbouncer3
4 = host=/tmp/pgbouncer4
社区洞见与替代方案
围绕该实现的技术讨论指出了若干替代方案和在扩展 PostgreSQL 连接池时的考虑因素:
- 替代连接池器: 有用户建议使用 Odyssey 或 pgdog 作为可扩展的 PgBouncer 替代方案。
- 基础设施层面的扩展: 通过 Kubernetes 运行多个 PgBouncer 实例被视为在多台机器上实现类似效果的直接方式,这有助于降低云服务商 VM 维护带来的风险。
- 架构层面的疑问: 部分工程师质疑此方案相较于使用传统的 HAProxy 将流量分发到多个 PgBouncer 实例的优势。
"取消请求落在一个从未见过该查询的进程上,什么也不会发生。Peering 解决了这个问题。进程之间相互了解,因此错误进程收到的取消请求会被转发到真正拥有该会话的进程。"
该 peering 机制对于在多进程 PgBouncer 环境中保持 PostgreSQL 连接管理功能至关重要。
摘要: ClickHouse 通过在单台机器上部署多个进程并使用 SO_REUSEPORT 与 peering 机制来处理会话特定请求(如查询取消),实现了 PgBouncer 吞吐量的 4 倍提升。
标题: 将 PgBouncer 吞吐量提升 4 倍:使用 SO_REUSEPORT 与 Peering