在 PostgreSQL 垂直扩展受限于单机硬件资源的背景下,水平扩展已成为大规模数据处理系统的必选路径。传统方案往往要求应用层感知分片逻辑或在数据库端部署扩展,这一约束显著增加了迁移成本与运维复杂度。PgDog 作为一款 Rust 编写的 PostgreSQL 代理层产品,尝试在应用与数据库之间构建透明的分片抽象,使客户端无需任何修改即可获得水平扩展能力。本文从分片路由、连接池化与架构设计三个维度,解析其核心实现机制与工程实践要点。
代理层的定位与职责
PgDog 定位为 OSI 第七层(应用层)代理,直接解析 PostgreSQL Wire 协议。它同时承担三种角色:连接池管理器、负载均衡器与数据库分片器。这三种能力在同一进程中实现,而非通过多个独立组件组合,这种集成设计有助于减少网络跳数与上下文切换开销。PgDog 不依赖数据库端扩展,部署时仅需在应用与 PostgreSQL 之间增加一层代理进程即可,这正是其「零改动」承诺的技术基础。
代理层启动后会读取两个配置文件:pgdog.toml 定义数据库集群拓扑、分片规则与连接池参数,users.toml 定义认证凭证。配置生效后,PgDog 对外暴露单一端点,客户端将其视为普通 PostgreSQL 服务器连接,而分片细节被完全隐藏在后端拓扑之中。
透明分片路由的实现机制
分片功能的核心在于路由决策的透明性。PgDog 采用声明式配置定义分片策略:在 pgdog.toml 中为同一逻辑数据库声明多个后端节点,每个节点标记独立的 shard 编号。例如,两分片集群可配置为两个数据库条目,分别指向不同的物理实例并标记 shard = 0 与 shard = 1。逻辑上这些后端被视为同一数据库的物理分片,客户端无需感知底层拓扑。
路由算法与 PostgreSQL 原生分区机制保持一致。PgDog 支持 HASH、LIST 与 RANGE 三种分片函数,这些函数与 PostgreSQL 的 PARTITION BY 语法采用相同的底层算法。这意味着在同一分片键条件下,PgDog 与 PostgreSQL 原生分区表对数据分布的判断是一致的。这一设计使得分片集群可以与 postgres_fdw 等原生特性共存,为渐进式迁移提供了技术兼容性。
路由决策分为两种场景。当 SQL 查询包含分片键且可精确定位时,例如 SELECT * FROM users WHERE user_id = $1,PgDog 通过解析查询提取分片键值,计算目标分片编号后将请求直接发送至对应后端。这种「直接路由」是分片系统的最优路径,可将查询负载均匀分布至各分片节点。当查询未包含分片键或涉及跨分片操作时,PgDog 将查询广播至所有分片节点,收集结果后在内存中完成聚合、排序与转换,最终以单结果集形式返回客户端。目前支持的跨分片操作包括聚合函数(count、sum、avg、min、max 等)、ORDER BY 与 GROUP BY 条件,以及多行 INSERT 语句的自动拆分。
对于跨分片写事务,PgDog 支持 PostgreSQL 两阶段提交协议。当客户端发送 COMMIT 时,代理层会转换为 PREPARE TRANSACTION 与 COMMIT PREPARED 的完整两阶段流程,确保即使在节点故障场景下也能维持原子性。若客户端在两阶段之间断开连接,PgDog 会根据事务状态自动执行回滚或提交,从而避免悬挂事务导致的数据不一致。
分片键管理与在线扩容
分片键的选择直接影响路由效率。PgDog 在配置中通过 sharded_tables 声明分片表及其分片列,例如 column = "user_id" 会将该列作为默认分片键。系统支持两种分片粒度:一是基于表列的分片,常见于用户 ID、订单 ID 等业务主键;二是基于 Schema 的分片,适用于多租户场景,不同租户的数据落入不同的 Schema,PgDog 根据 search_path 或完全限定表名自动路由至对应分片。
在线扩容是分片系统的高频需求。PgDog 实现了基于逻辑复制的在线重分片能力,扩容过程分为五个步骤:首先创建目标分片数量的空集群;然后通过 schema-sync 命令将表结构同步至新节点;接着运行 data-sync 命令利用逻辑复制协议并行迁移历史数据;迁移期间持续同步增量更新;最后通过 MAINTENANCE ON、RELOAD 与 MAINTENANCE OFF 的序列操作完成流量切换。整个过程无需停机,且不依赖 etcd 或 Zookeeper 等外部协调组件,简化了运维复杂度。
连接池与负载均衡
连接池是 PostgreSQL 代理层的标配能力,PgDuck 在此基础上进一步实现了与分片逻辑的深度整合。连接池支持 session 模式与 transaction 模式:session 模式下连接在整个客户端会话期间保持复用;transaction 模式下连接在事务结束后即释放回池,供其他客户端复用。两种模式可并存,系统根据客户端的声明自动选择。
与 PgBouncer 的关键差异在于 PgDog 对 SQL 上下文的处理能力。它能够解析 SET 语句与启动参数,在连接池中为不同客户端正确设置会话状态。例如,当两个客户端使用不同的 search_path 时,PgDog 会在复用后端连接前重置相关会话变量,确保不会发生状态泄露。此外,PgDog 实现了被遗弃事务的自动回滚与连接同步机制,可在应用异常断开时快速回收资源,避免后端连接因事务未提交而被长期占用。
负载均衡方面,PgDog 支持三种策略:轮询(round-robin)、随机(random)与最少活跃连接(least active connections)。在主从拓扑中,系统会自动识别 primary 与 replica 角色,将写操作与 SELECT 发送至不同节点。健康检查机制会实时监控后端状态,故障节点会被自动移除并在恢复后重新加入流量。
工程实践参数与监控建议
部署 PgDog 时,以下参数值得重点关注。default_pool_size 控制每个后端的默认连接池大小,建议根据后端机器规格与查询复杂度设置为 10 至 50 不等;过高可能导致后端连接数成为瓶颈,过低则削弱池化效益。lsn_check_delay 控制复制延迟检查频率,设为 0 时启用实时复制状态监控,适用于需要快速感知主从切换的场景。rewrite.shard_key 与 rewrite.split_inserts 控制分片键更新与多行插入的自动改写行为,可设为 rewrite(自动处理)、ignore(静默丢弃)或 error(拒绝执行)。
监控层面,PgDog 同时暴露 PgBouncer 风格的管理数据库与 OpenMetrics 接口。建议优先使用 OpenMetrics 导出至 Prometheus 或 Datadog,关键指标包括:客户端活跃连接数、后端连接池利用率、查询路由命中率(直接路由 vs 跨分片广播)以及各分片的查询延迟分布。这些指标有助于识别热点分片或路由异常,是容量规划与性能调优的数据基础。
小结
PgDog 通过在代理层集成连接池、负载均衡与分片路由三大能力,为 PostgreSQL 提供了一种无侵入的水平扩展路径。其核心价值在于将分片拓扑从应用层下沉至基础设施层,使现有客户端无需修改即可获得水平扩展能力。分片函数与 PostgreSQL 原生分区机制的对齐设计降低了学习成本,在线重分片能力则解决了扩容这一核心痛点。对于面临单机容量瓶颈、但又希望保持 PostgreSQL 生态与 SQL 完整性的团队,PgDog 提供了一条值得评估的技术路径。
资料来源:PgDog 官方 GitHub 仓库(https://github.com/pgdogdev/pgdog)与架构文档(https://docs.pgdog.dev/architecture/)。