PgDog
PgDog 是一个用 Rust 编写的高性能 Postgres 代理(PgCat 的继任者)。它提供连接池化、跨副本的读写负载均衡,以及水平分片,位于一个或多 个 PostgreSQL 后端之前。pgcli 可将 PgDog 作为独立的顶层插件运行:它是共享 基础设施,而非依附某个实例的 sidecar。
安全提示: PgDog 使用
users.toml中的明文密码对客户端做认证。 pgcli 以0600权限写出该文件并只读挂载进容器,但密码仍以明文存在于磁盘和pg.yaml中。请将监听端口保持在回环地址(默认)或可信网络内,并把配置文件 当作机密对待。
PgDog 由两个 TOML 文件配置——pgdog.toml(代理本身、其后端、以及分片规则)
和 users.toml(客户端凭据)。pgcli 完全根据安装参数生成这两个文件:没有
需要手工编辑的配置文件,因此 pg addon install pgdog 就是唯一事实来源,且具
有幂等性——重新执行会根据所给参数重新渲染文件。
平台支持
PgDog 支持 Linux(host 网络)与 macOS 单主机 dev/test:macOS 下容器加
入 PG 实例在 podman machine 里使用的同一张 pgcli-net bridge 网络,并发布客户
端与 openmetrics 两个端口。macOS 上:
- 容器内的监听地址会被自动放宽为
0.0.0.0,否则发布端口转发不到只绑回环的进 程;对外连接的地址仍然是127.0.0.1:<port>。 - 后端必须是从 bridge 可达的地址。 PgDog 不会自动解析
--backend里的名字, 所以127.0.0.1指向的是 Mac 本机,而不是 podman machine 虚拟机。请给每个--backend填目标实例的容器名(用pg status -i <instance>查看Container:一行,例如app=pgcli-pg-mypg:5432:...),或 Mac 能路由到的地 址 —— 对受管实例绝对不要填127.0.0.1。
工作原理
- 共享基础设施: PgDog 存放在
pg.yaml顶层的addons.pgdogmap 中,按 代理名索引——不隶属于任何单个实例。 - 主机网络(Linux)/ bridge 网络(macOS): 代理监听其客户端端口(从
pgdog_start_port自动分配,默认 7432),并在下一个空闲端口提供 Prometheus 风格的 openmetrics 端口。Linux 上以--network host运行;macOS 上加入pgcli-net并发布两个端口。 - 生成的配置:
pgdog.toml+users.toml写在<base-dir>/addon/pgdog/<name>/下,并绑定挂载进容器的/pgdog。 - 锁定镜像: 默认
ghcr.io/pgdogdev/pgdog:v0.1.57,可用--image覆盖。
安装
最小的单后端代理(仅演示连接池化,见下方说明):
加
--sharded-table是为了让这份示例成为完整、自洽的配置(与下方"分片与副 本"示例对齐)。注意:单个--backend无从分片——不管是否声明,所有数据最 终都会落到那唯一后端,所以这份最小示例只体现连接池化。真正分片需要至少两个不 同shard编号的--backend(见分片与副本)。
--backend NAME=HOST:PORT:DBNAME[:SHARD[:ROLE]]—— 一个[[databases]]条目。NAME是客户端连接时使用的逻辑数据库名;DBNAME是后端上真实的数据 库名。SHARD默认为 0;ROLE默认为 PgDog 默认值(primary,读路由可设replica)。可重复。--user NAME:PASSWORD[:DBNAME]—— 一个[[users]]条目。DBNAME是该用户 可访问的逻辑数据库(某个--backend的名字),缺省时取第一个后端的名字。可 重复。- 至少需要一个
--backend和一个--user。
其他参数:
| 参数 | 含义 | 默认值 |
|---|---|---|
--name |
代理 / 插件键名 | pgdog |
--port |
客户端主机端口(openmetrics 取下一个空闲端口) | 自动分配 |
--host |
监听地址 | 127.0.0.1 |
--pool-mode |
transaction 或 session |
transaction |
--workers |
工作线程数 | 2 |
--default-pool-size |
每个 user/db 对的服务器连接数 | 10 |
--image |
PgDog 镜像 tag | ghcr.io/pgdogdev/pgdog:v0.1.57 |
分片与副本
对每个分片 / 角色重复 --backend,并用
--sharded-table DBNAME:TABLE:COLUMN:DATA_TYPE 声明分片键:
这会把两个分片(各含一主一副本)置于逻辑数据库 app 之后,并按 id 列路由
users 表。
准备后端
PgDog 路由到的数据库、表与角色必须已存在于后端——安装代理并不会创建它们。对于
本地 pgcli 实例,用 pg exec 创建每个分片库、其分片表,以及登录角色。以单机
default 实例为例(分片即同一端口上的不同数据库),下面的示例先准备后端(第 1–4
步)、安装代理(第 5 步),再写入数据以体现路由效果(第 6–7 步):
pg exec -i default -- psql -d <db> 在指定实例的容器内针对某个数据库执行命令。
上面的 id bigint 列与 --sharded-table "app:users:id:bigint" 的声明一致,因
此 PgDog 能按 id 路由 users 的行。第 6、7 步让这层路由可见:两个分片的查询
返回互不重叠的 id 子集(具体划分取决于 PgDog 的哈希),两者合起来正好覆盖所
有写入行——没有一行会同时落到两个分片。远程后端则直接对各主机执行等价 SQL。
后端角色不可省略。 默认情况下 PgDog 用客户端的 --user 名字及其
users.toml 密码去连后端。所以每个后端都必须存在名为 appuser(等)的登录角
色,否则连接会失败并报 password for user "..." is wrong, or the database does not exist——即使在回环 trust 配置下密码被忽略,角色仍必须存在。若走密码认证
(非回环 scram-sha-256 的默认行为),users.toml 里的密码必须与角色一致。
解耦客户端与后端用户。 PgDog 本身支持用不同于客户端的用户去连后端:一个
[[users]]条目可带server_user/server_password,一个[[databases]]条目可带user/password(后者优先级更高)。但 pgcli 的安装参数目前不会 生成这些字段,因此经pg addon install pgdog安装时,后端角色名始终等于--user的名字。若你需要一个共享的后端角色(例如统一的postgres超级用户, 或与所有客户端用户名都不同的名字),只能手工编辑生成的users.toml/pgdog.toml并重启容器——但请注意:重新执行 install 会按参数重新 生成这两个文件,覆盖掉你的手工改动。
连接
安装摘要会打印接入端点。客户端通过代理的客户端端口连接,使用逻辑数据库名和某个
--user 凭据——在 pgcli 里,就是一个指向代理的 --dsn:
Prometheus 指标在 openmetrics 端口提供:
向分片写入
写入如何落到各分片,取决于语句的形式。以下是在 PgDog v0.1.57 上的实测。
单行 INSERT —— 按分片键路由。 一条语句只带一个 VALUES 元组时,
PgDog 对 id 做哈希,把该行送到唯一一个分片:
以六条单行语句分别插入 id 1–6 时,两分片各得一部分(一次实测:shard0 收到
1,2,shard1 收到 3,4,5,6 —— 具体划分取决于 PgDog 的哈希,不应当作可依赖
的结果)。没有任何一行同时落入两个分片。
多行 INSERT —— 广播而非拆分。 一条语句带多个 VALUES 元组时,会被原
样送到每一个分片,于是每个分片都拿到全部行:
这条语句报告 INSERT 0 8 —— 每个分片各 4 行。分片内 PRIMARY KEY 仍然
有效(重复 id 分别落在不同分片,永不冲突),且没有任何错误或告警:每个分
片静默地多出一份完整副本。随后经代理读取就会看到每个 id 都成对重复出现。
正确的批量导入方式: 一条语句一行、逐行经代理插入(各行单独路由);或者
绕开代理,直接对各分片做导入(例如 pg exec -i <inst> -- psql -d <shard> 跑
COPY)。
配置
安装后,pg.yaml 在顶层 addons.pgdog 下记录每个代理:
端口基址可通过顶层 pgdog_start_port(默认 7432)配置;openmetrics 端口总是紧接
其上方分配。
查看列表
每个 PgDog 代理都会出现在 Infra add-ons (pgdog) 小节下,附带运行时状态、 端口、后端 / 用户数量、镜像和容器名:
Backends / Users 取自 pgdog.toml / users.toml 中的条目数;Status
反映容器的实时状态(已停止的代理显示为 stopped)。
启动与停止
宿主机重启或手动停掉后,无需重跑 install 即可拉起代理(配置与 users 不动):
start 幂等 —— 已在运行则不动;容器被删掉的代理会从其配置目录重建。
开机自启
容器带有 --restart unless-stopped 策略(应对崩溃,而非重启)。要在主机重启后
拉起代理:
这会设置 autostart: true 并安装 / 刷新开机服务(见
开机自启)。开机时是仅启动语义:它启动已存在的容器、读
取磁盘上已有的 pgdog.toml/users.toml,不会重新生成配置或认证。请先安装代理。
pg autostart status 会列出每个目标的状态。
日志
PgDog 以结构化 INFO 行记录连接池事件(新建服务器连接、认证、客户端连接 / 断
开)。若某个连接池不断重试并报 password for user "..." is wrong, or the database does not exist,说明上面「准备后端」的第 3 或第 4 步被跳过——后端没有
该登录角色,或其密码与 users.toml 不一致。
注意事项
- 重装幂等: 重新执行
pg addon install pgdog --name <p>会根据所给参数重新 渲染配置并重建容器。后端 / 用户 / 分片列表被本命令的参数完全替换——省略某 个--backend是移除它,而非保留。 - 明文凭据: 密码存放在
users.toml和pg.yaml中。建议为代理用户单独使 用一个低权限角色,并限制对客户端端口的网络访问。 - 写入形式差异: 单行
INSERT按分片键路由;多行INSERT VALUES会被广 播到每个分片。详见向分片写入。 - 非实例级 sidecar: 与 PgBouncer 不同,PgDog 通过
--backend里的地址指向 后端——它不必指向某个 pgcli 管理的实例,一个代理可横跨多个数据库 / 分片。