Table of Contents
- pgdog 从原理到实践
- 一、pgdog 原理篇
- 二、配置项详解篇
- 2.1 pgdog.toml — [general] 全量配置项
- 2.1.1 监听与运行时
- 2.1.2 连接池核心参数
- 2.1.3 认证
- 2.1.4 超时控制(单位:毫秒)
- 2.1.5 健康检查
- 2.1.6 读写分离与负载均衡
- 2.1.7 查询解析
- 2.1.8 日志与监控
- 2.1.9 TLS
- 2.1.10 连接恢复
- 2.1.11 高级特性
- 2.2 pgdog.toml — [admin] 段
- 2.3 pgdog.toml — [[databases]] 段
- 2.4 users.toml — [[users]] 段
- 三、最佳实践案例篇
- 因此生产环境不能简单按照理论最大值配置,而应该结合业务峰值压测。
- 四、运维管理篇
- 五、性能调优篇
- 5.1 压测数据分析
- 5.2 配置优化逐项分析
- 问题 1:`default_pool_size = 10` 过大(🔴 高优先级)
- 问题 2:`min_pool_size = 0` 无预热(🟡 中优先级)
- 问题 3:`healthcheck_interval = 300000`(5分钟)过长(🟡 中优先级)
- 问题 4:`idle_timeout = 600000`(10分钟)偏长(🟡 中优先级)
- 问题 5:`query_timeout = 300000`(5分钟)过长(🟡 中优先级)
- 问题 6:`checkout_timeout = 5000`(5秒)可能不够(🟢 低优先级)
- 问题 7:`log_connections = true` + `log_disconnections = true` 日志量大(🟢 低优先级)
- 问题 8:query_cache 命中率低(11.4%)(🟢 低优先级,预期行为)
- PG 侧优化
- 5.3 参数调优建议
- 5.4 监控指标说明
- 5.5 Prometheus 告警建议
- 六、编译安装篇
- 七、踩坑实录与常见陷阱
- 7.1 超时参数不支持时间单位字符串
- 7.2 psql 默认走 Unix socket 导致连不上 pgdog
- 7.3 users.toml 的 password 字段必须用明文密码
- 7.4 [admin] 段的 password 也必须用明文
- 7.5 SHOW POOLS 等管理命令必须在 admin 库执行
- 7.6 pgdog.toml 与 users.toml 中的 admin 用户是两套体系
- 7.7 role="auto" + LSN 检查禁用导致 checkout timeout(最关键陷阱)
- 7.8 transaction 模式下 PG 日志出现 prepared statement does not exist 错误
- 7.9 pgdog hash 生成的密码与 pg_authid 中不同
- 7.10 踩坑速查表
- 八、命令行工具
- 附录
pgdog 从原理到实践
基于 openEuler 22.03 LTS-SP4 (aarch64, 8核) 环境实战整理
一、pgdog 原理篇
1.1 架构概览
pgdog 是 PostgreSQL 生态中功能最全面的连接池、代理、负载均衡器和查询路由器,使用 Rust + Tokio 异步框架构建,核心能力矩阵:
| 能力 | 说明 |
|---|---|
| 连接池 | 支持 transaction / session 两种池化模式,将数千客户端连接收敛为少量后端连接 |
| 读写分离 | 基于 PgQuery (libpg_query) 对每条 SQL 做 AST 解析,自动识别读写,路由到正确角色节点 |
| 负载均衡 | 支持 random / round_robin / least_active_connections / weighted_round_robin |
| 分片 | 数据库级水平分片,透明路由查询到正确分片,支持 resharding |
| 查询缓存与重写 | prepared statement 缓存、查询结果重写 |
| 健康检查 | 实时检测后端健康状态,自动剔除/恢复故障节点 |
| 故障切换 | role=auto 自动感知主备切换,配合 Patroni 实现零停机 |
| 多租户 | 支持 multi_tenant 隔离,不同用户/database 的池完全独立 |
架构层级关系:
客户端 (psql / pgbench / App) │ ▼ pgdog (0.0.0.0:6432) ← Tokio 异步运行时 (workers 个线程) ├── Frontend 层:接收客户端连接、协议解析、认证 ├── Query Parser 层:PgQuery AST 解析 + 查询缓存 ├── Router 层:读写分离决策、分片路由 ├── Pool Manager 层:连接池管理、健康检查、统计 └── Backend 层:与 PostgreSQL 后端连接管理 │ ▼ PostgreSQL (127.0.0.1:5433) ├── database 1: db_biz_01 ├── database 2: db_biz_02 ├── ... └── database N: db_biz_40
1.2 请求处理链路
一个客户端查询经过 pgdog 的完整链路:
客户端连接 │ ├─► [Frontend] 接收连接 → 协议握手 (SSL/StartupMessage) │ │ ├─► [Auth] 认证检查:查 users.toml → SCRAM/MD5/Trust 验证 │ │ ├─► [Router] StartupMessage 提取 database + user │ │ → 查找对应连接池 (user, database) 组合 │ │ → 若不存在 → 自动创建或报错 │ │ ├─► [Pool] 从 (user, database) 池获取/创建后端连接 │ │ → 池满:等待 checkout_timeout → 超时报错 │ │ → 有可用连接:取出 → 健康检查通过 → 分配 │ │ ├─► [Parser] 对每条 SQL 做 AST 解析 (libpg_query) │ │ → 识别 DML/DQL → 决定 read/write │ │ → 提取表名 + WHERE 条件 → 分片路由决策 │ │ ├─► [Router] 根据解析结果: │ │ → Write → 路由到 primary │ │ → Read → 路由到 replica (负载均衡策略) │ │ ├─► [Execute] 转发查询到后端 PG 连接 │ │ → 等待结果 → 回传给客户端 │ │ └─► [Release] 事务结束(pooler_mode=transaction) 或 会话结束(pooler_mode=session) → 归还连接到池 → 执行连接状态清理机制
连接状态清理可能包括:
-
RESET ALL
-
DEALLOCATE ALL
-
DISCARD ALL
-
其他内部状态清理逻辑
具体行为取决于 pgdog 当前版本实现。
1.3 连接池模式详解
pgdog 的连接池以 (user, database_name) 为粒度——同一池内按 role 区分 primary/replica 连接。实际使用中最关键的是 pooler_mode:
Transaction 模式(默认推荐)
客户端 A: BEGIN → SELECT → UPDATE → COMMIT │ │ ▼ ▼ 后端连接 1: [被 A 独占...] → 归还到池 → 执行连接状态清理 │ 客户端 B: ──► 获取同一个后端连接 → BEGIN → SELECT → COMMIT 特点: • 事务结束后立即归还连接,连接复用率高 • 连接归还池时会执行状态清理机制,确保后续客户端复用时不会继承前一个客户端的 session 状态 • 具体清理方式取决于 pgdog 版本和配置,可能采用 DISCARD ALL 或等价处理 • 适合:短连接、PHP/Web 应用、无状态 API • **支持 prepared statement**:pgdog 在 extended 模式下负责管理协议级 prepared statement 生命周期 • 限制:依赖 session 生命周期的状态无法跨事务保持,例如 SET、临时表、LISTEN/NOTIFY 等 • ⚠️ **必须注意 role 配置**:单主库场景必须用 `role = "primary"`,`role = "auto"` 依赖 pgdog 的角色检测机制,如果配置不完整可能导致 checkout timeout(见 7.7)
Session 模式
客户端 A: 连接建立 → 分配专属后端连接 客户端 B: 连接建立 → 分配专属后端连接 特点: • 客户端整个会话独占一个后端连接 • 支持所有 PG 特性(SET、LISTEN/NOTIFY、cursor) • 客户端可直接使用 PG 原生 prepared statement(连接独占,状态持久) • pgdog 的 prepared statement 代理/缓存机制自动禁用(源码逻辑),直通后端 • 适合:长连接、有状态应用、需要 session 级别状态 • 限制:连接复用率为零,需要大量后端连接
⚠️ 源码中的关键逻辑(pgdog-config/src/core.rs):
// Session 模式下自动禁用 prepared_statements 代理
pub fn prepared_statements(&self) -> PreparedStatements {
if self.config.general.pooler_mode == PoolerMode::Session {
PreparedStatements::Disabled
} else {
self.config.general.prepared_statements
}
}
注意:Session 模式禁用的是 pgdog 的 prepared statement 代理/缓存机制(即 pgdog 不再在中间层管理 Parse/Bind/Execute 的映射),而非禁止客户端使用 prepared statement。由于 Session 模式下连接是独占的,客户端可以直接与 PG 建立 prepared statement,状态在会话内持久。
1.4 用户认证与 all_databases 机制
pgdog 的用户认证有两层:
| 层 | 说明 | 配置位置 |
|---|---|---|
| 客户端 → pgdog | auth_type 控制 (scram/md5/trust) |
pgdog.toml [general] |
| pgdog → 后端 PG | server_auth 控制 (password/rds_iam/vault) |
users.toml [users] |
说明:
server_auth = "password"表示"使用 users.toml 中的server_password静态密码"进行后端认证,与auth_type的md5/scram/trust(认证协议)不是同一层面的概念。
注意:
server_auth = "password"表示 pgdog 使用配置文件中的静态密码连接 PostgreSQL。它不是 PostgreSQL authentication method 中的 password/md5/scram 类型。两者属于不同层:
all_databases 机制(源码 pgdog-config/src/users.rs):
User 结构体有三个互斥的数据库绑定方式:
| 字段 | 类型 | 说明 | 优先级 |
|---|---|---|---|
database |
String |
绑定单个数据库 | 最低,与 databases 互斥 |
databases |
Vec<String> |
绑定多个指定数据库 | 中 |
**all_databases** |
**bool** |
绑定 pgdog.toml 中所有数据库 | 最高 |
源码中的冲突检测逻辑(Users::check()):
if user.all_databases && (!user.databases.is_empty() || !user.database.is_empty()) {
warn!("user is configured for all databases and a specific database, defaulting to all databases");
}
工作流程:pgdog 启动/RELOAD 时,对所有 all_databases = true 的用户,自动为 Config 中的每个数据库生成一份克隆用户配置:
// databases.rs:640-669 (简化)
if user.all_databases {
config.databases.keys()
.map(|database| {
let mut user = user.clone();
user.database = database;
user
})
.collect()
}
这意味着:一条 [[users]] + all_databases = true = 自动为每个 [[databases]] 创建独立的 (user, database) 连接池。
1.5 配置优先级体系
pgdog 的配置项有三个级别,从高到低:
per-user 级别 (users.toml [[users]]) │ 覆盖 ▼ per-database 级别 (pgdog.toml [[databases]]) │ 覆盖 ▼ global 级别 (pgdog.toml [general])
可被覆盖的参数包括:
| 参数 | global | per-database | per-user |
|---|---|---|---|
pool_size |
default_pool_size |
pool_size |
pool_size |
min_pool_size |
min_pool_size |
min_pool_size |
min_pool_size |
pooler_mode |
pooler_mode |
pooler_mode |
pooler_mode |
idle_timeout |
idle_timeout |
idle_timeout |
idle_timeout |
statement_timeout |
— | statement_timeout |
statement_timeout |
lock_timeout |
— | lock_timeout |
lock_timeout |
read_only |
— | read_only |
read_only |
server_lifetime |
server_lifetime |
server_lifetime |
server_lifetime |
二、配置项详解篇
以下配置项基于 pgdog 源码中
General、Database、Userstruct 的完整字段,含默认值和说明。
2.1 pgdog.toml — [general] 全量配置项
2.1.1 监听与运行时
| 配置项 | 类型 | 默认值 | 说明 | 热重载 |
|---|---|---|---|---|
host |
String |
0.0.0.0 |
监听地址。绑定所有网卡或指定 IP | ❌ |
port |
u16 |
6432 |
监听端口 | ❌ |
workers |
usize |
2 |
Tokio 异步工作线程数。建议 CPU 核数 × 0.5~1,多核系统建议每 2 个 vCPU 配 1 个 worker | ❌ |
workers 调优:8 核机器建议
4~8。0表示使用单线程 current_thread runtime(仅调试场景)。
2.1.2 连接池核心参数
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
default_pool_size |
usize |
10 |
每个 (user,db) 池的最大后端连接数。强烈建议远低于 PG max_connections,为运维预留连接 |
min_pool_size |
usize |
1 |
每个池最小保持连接数。启动时即创建,减少首次请求延迟 |
pooler_mode |
PoolerMode |
transaction |
transaction:事务结束归还;session:会话结束归还 |
注意:
default_pool_size也可写作max_pool_size(别名,源码兼容)。
2.1.3 认证
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
auth_type |
AuthType |
scram |
客户端认证方式:scram / md5 / trust |
passthrough_auth |
PassthroughAuth |
disabled |
认证透传:客户端密码直传给后端 PG。enabled 需 TLS,enabled_plain 无需 TLS。启用后 users.toml 中的 password 可为空 |
2.1.4 超时控制(单位:毫秒)
⚠️ 重要:pgdog 的超时参数类型为
u64(毫秒整数),不支持"5s"/"10m"等时间单位字符串。这与 PgBouncer 不同,详见 7.1 超时参数不支持时间单位字符串。
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
connect_timeout |
u64 |
5_000 |
创建后端连接超时 (ms) |
connect_attempts |
u64 |
1 |
连接重试次数 |
connect_attempt_delay |
u64 |
0 |
重试间隔 (ms) |
checkout_timeout |
u64 |
5_000 |
池满时客户端等待获取连接的超时 (ms) |
idle_timeout |
u64 |
60_000 |
超过 min_pool_size 的空闲连接存活时间 (ms) |
client_idle_timeout |
u64 |
MAX (无限) |
客户端空闲超时 (ms),超时断开 |
client_idle_in_transaction_timeout |
u64 |
MAX (无限) |
客户端事务中空闲超时 (ms) |
client_login_timeout |
u64 |
60_000 |
客户端登录认证超时 (ms) |
query_timeout |
u64 |
MAX (无限) |
单条查询最大执行时间 (ms) |
rollback_timeout |
u64 |
5_000 |
连接归还时 ROLLBACK 超时 (ms) |
server_lifetime |
u64 |
86_400_000 |
后端连接最大存活时间 (ms),默认 24 小时。到期归还池时关闭 |
server_lifetime_jitter |
u64 |
0 |
server_lifetime 抖动范围 (ms),防止集中过期 |
shutdown_timeout |
u64 |
60_000 |
关闭时等待活跃事务完成的超时 (ms) |
shutdown_termination_timeout |
Option<u64> |
None |
shutdown_timeout 过期后强制终止的超时 (ms)。设置后 pgdog 会向 PG 发送 CANCEL 请求 |
2.1.5 健康检查
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
healthcheck_interval |
u64 |
30_000 |
健康检查间隔 (ms) |
healthcheck_timeout |
u64 |
5_000 |
健康检查超时 (ms) |
idle_healthcheck_interval |
u64 |
30_000 |
空闲连接健康检查间隔 (ms) |
idle_healthcheck_delay |
u64 |
5_000 |
启动后延迟空闲健康检查的时间 (ms) |
healthcheck_port |
Option<u16> |
None |
负载均衡器 HTTP 健康检查端口 |
ban_timeout |
u64 |
300_000 |
故障封禁自动解封时间 (ms),默认 5 分钟 |
ban_replica_lag |
u64 |
MAX (不限制) |
副本延迟超过此毫秒数即封禁 |
ban_replica_lag_bytes |
u64 |
MAX (不限制) |
副本延迟超过此字节数即封禁 |
2.1.6 读写分离与负载均衡
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
load_balancing_strategy |
enum |
random |
random / round_robin / least_active_connections / weighted_round_robin |
read_write_strategy |
enum |
conservative |
conservative:显式事务路由到主库;aggressive:检查事务第一条语句决定 |
read_write_split |
enum |
include_primary |
include_primary:主库也分担读;exclude_primary:主库只写;prefer_primary:读请求优先路由到主库,主库压力大时自动分流到副本 |
2.1.7 查询解析
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
prepared_statements |
enum |
extended |
disabled / extended / full。Session 模式下代理机制自动禁用 |
prepared_statements_limit |
usize |
MAX (无限制) |
每服务端连接最大 prepared statement 数 |
query_parser |
QueryParserLevel |
auto |
查询解析器:auto / on / off |
query_parser_engine |
enum |
pg_query |
底层解析引擎(基于 libpg_query) |
query_cache_limit |
usize |
1_000 |
语句缓存大小 |
query_size_limit |
Option<usize> |
None |
查询消息大小限制 (bytes) |
query_size_limit_action |
enum |
warn |
超限动作:warn 记录日志 / block 拒绝并断开 |
log_min_duration_parse |
Option<u64> |
None |
解析耗时超过此值记录 WARN 日志 (ms) |
log_query_sample_length |
usize |
1000 |
日志中查询文本最大字符数 |
2.1.8 日志与监控
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
log_level |
String |
info (from RUST_LOG) |
日志级别,同 RUST_LOG 语法 |
log_format |
enum |
text |
text / json / json_flattened |
log_connections |
bool |
true |
记录客户端连接 |
log_disconnections |
bool |
true |
记录客户端断开 |
log_dedup_window |
u64 |
0 (关闭) |
日志去重窗口 (ms) |
log_dedup_threshold |
u64 |
0 (关闭) |
窗口内允许的重复日志数 |
openmetrics_port |
Option<u16> |
None |
Prometheus metrics 端口 |
openmetrics_namespace |
Option<String> |
None |
metrics 前缀 |
stats_period |
u64 |
15_000 |
SHOW STATS 和 Prometheus 指标统计周期 (ms) |
2.1.9 TLS
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
tls_certificate |
Option<PathBuf> |
None |
TLS 证书路径 |
tls_private_key |
Option<PathBuf> |
None |
TLS 私钥路径 |
tls_client_required |
bool |
false |
拒绝非 TLS 连接 |
tls_verify |
TlsVerifyMode |
prefer |
后端 TLS 验证:prefer / verify_full / disabled |
tls_server_ca_certificate |
Option<PathBuf> |
None |
验证后端证书的 CA 证书 |
tls_client_ca_certificate |
Option<PathBuf> |
None |
验证客户端证书的 CA 证书 |
2.1.10 连接恢复
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
connection_recovery |
enum |
recover |
后端连接恢复策略:recover / drop |
client_connection_recovery |
enum |
drop |
客户端连接恢复策略 |
dry_run |
bool |
false |
单分片部署下启用查询解析器并记录决策,不实际路由 |
2.1.11 高级特性
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
two_phase_commit |
bool |
false |
跨分片写事务启用两阶段提交 |
two_phase_commit_auto |
Option<bool> |
None |
自动将单语句写事务转为 2PC |
two_phase_commit_wal_dir |
Option<PathBuf> |
./pgdog_wal |
2PC WAL 目录 |
cross_shard_disabled |
bool |
false |
全局禁用跨分片查询 |
dns_ttl |
Option<u64> |
None |
DNS 记录 TTL 覆盖 (ms) |
pub_sub_channel_size |
usize |
0 (关闭) |
pub/sub 后台任务队列大小,>0 启用 |
lsn_check_interval |
u64 |
5_000 |
LSN 复制延迟检查间隔 (ms) |
lsn_check_timeout |
u64 |
5_000 |
LSN 检查超时 (ms) |
lsn_check_delay |
u64 |
MAX (关闭) |
LSN 检查延迟启动。设为 0 表示启动后立即开始 LSN 检查(启用自动故障切换检测) |
mirror_queue |
usize |
128 |
镜像数据库队列大小 |
mirror_exposure |
f32 |
1.0 |
镜像流量占比 (0.0~1.0) |
query_log |
Option<PathBuf> |
None |
查询日志文件路径(生产慎用,性能开销大) |
query_log_stdout |
bool |
false |
查询日志输出到标准输出 |
2.2 pgdog.toml — [admin] 段
[admin]
name = "admin" # 管理数据库名(默认 admin)
user = "admin" # 管理用户名(默认 admin)
password = "..." # 管理密码(必须用明文,不支持 SCRAM 哈希)
# 不设置则随机生成 _pgdog_XXXXXXXXXXXX
# debug 模式下启动日志会打印密码
注意:
2.3 pgdog.toml — [[databases]] 段
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
name |
String |
必填 | 客户端连接时使用的数据库名 |
host |
String |
必填 | 后端 PG 地址 |
port |
u16 |
5432 |
后端 PG 端口 |
role |
enum |
primary |
primary / replica / auto |
shard |
usize |
0 |
分片编号(从 0 开始) |
database_name |
Option<String> |
None |
后端实际数据库名(与 name 不同时指定) |
user |
Option<String> |
None |
后端连接用户(覆盖 users.toml 的 server_user) |
password |
Option<String> |
None |
后端连接密码(覆盖 users.toml 的 server_password) |
pool_size |
Option<usize> |
None |
覆盖 default_pool_size |
min_pool_size |
Option<usize> |
None |
覆盖全局 min_pool_size |
pooler_mode |
Option<PoolerMode> |
None |
覆盖全局 pooler_mode |
statement_timeout |
Option<u64> |
None |
连接级 statement_timeout (ms) |
lock_timeout |
Option<u64> |
None |
连接级 lock_timeout (ms) |
idle_timeout |
Option<u64> |
None |
覆盖全局 idle_timeout (ms) |
read_only |
Option<bool> |
None |
强制连接为只读模式 |
server_lifetime |
Option<u64> |
None |
覆盖全局 server_lifetime (ms) |
server_lifetime_jitter |
Option<u64> |
None |
覆盖全局 server_lifetime_jitter (ms) |
lb_weight |
u8 |
255 |
加权负载均衡权重 (0~255) |
resharding_only |
bool |
false |
仅用于 resharding,不服务常规流量 |
2.4 users.toml — [[users]] 段
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
name |
String |
必填 | 用户名 |
database |
String |
"" |
绑定单个数据库 |
databases |
Vec<String> |
[] |
绑定多个数据库 |
**all_databases** |
**bool** |
**false** |
绑定所有数据库(优先级最高) |
password |
Option<String> |
None |
客户端认证密码(必须用明文,不支持 SCRAM 哈希) |
passwords |
Vec<String> |
[] |
多个密码(全部尝试) |
password_hash |
Option<String> |
None |
密码哈希(不存明文密码,配合 server_auth 使用) |
pool_size |
Option<usize> |
None |
覆盖 default_pool_size(per-user 最高优先级) |
min_pool_size |
Option<usize> |
None |
覆盖全局 min_pool_size |
pooler_mode |
Option<PoolerMode> |
None |
覆盖全局 pooler_mode |
server_user |
Option<String> |
None |
后端 PG 连接用户名(默认同 name) |
server_password |
Option<String> |
None |
后端 PG 连接密码(默认同 password) |
server_auth |
ServerAuth |
password |
后端认证方式:password(使用 server_password 静态密码)/ rds_iam / azure_workload_identity / vault_dynamic / vault_static |
server_iam_region |
Option<String> |
None |
RDS IAM 区域 |
server_vault_path |
Option<String> |
None |
Vault credentials 路径 |
vault_path |
Option<String> |
None |
用于验证客户端密码的 Vault static role 路径 |
vault_refresh_percent |
Option<u8> |
None |
Vault 凭证刷新阈值百分比 (1~80) |
identity |
Option<String> |
None |
mTLS 用户身份 |
statement_timeout |
Option<u64> |
None |
连接级 statement_timeout (ms) |
lock_timeout |
Option<u64> |
None |
连接级 lock_timeout (ms) |
idle_timeout |
Option<u64> |
None |
覆盖全局 idle_timeout (ms) |
read_only |
Option<bool> |
None |
强制只读 |
replication_mode |
bool |
false |
启用 replication=database 连接参数 |
replication_sharding |
Option<String> |
None |
复制分片目标数据库 |
cross_shard_disabled |
Option<bool> |
None |
禁用跨分片查询 |
two_phase_commit |
Option<bool> |
None |
覆盖全局 2PC 设置 |
two_phase_commit_auto |
Option<bool> |
None |
覆盖全局 2PC auto 设置 |
schema_admin |
bool |
false |
拥有 DDL 提升权限的 schema 管理员 |
server_lifetime |
Option<u64> |
None |
覆盖全局 server_lifetime (ms) |
server_lifetime_jitter |
Option<u64> |
None |
覆盖全局 jitter (ms) |
三、最佳实践案例篇
3.1 案例一:多库多用户连接池(40业务库 + 系统库)
场景:
-
1 个 PG 实例 (127.0.0.1:5433),40 个业务库 + 3 个系统库:
-
postgres
-
template0
-
template1
-
-
所有库使用同一个用户
postgres,SCRAM-SHA-256 认证 -
8 核服务器
说明:template0 通常不会作为业务连接目标,因此实际管理库数量根据环境可能不同。
pgdog.toml
[general]
host = "0.0.0.0"
port = 6432
# 连接池核心
default_pool_size = 10 # 每 (user,db) 池上限
# 计算:1 用户 × 42 库 × 10 = 最多 420 连接
min_pool_size = 2 # 每池 2 个预热连接
pooler_mode = "transaction" # 事务级复用
# 认证(生产环境)
auth_type = "scram" # 推荐使用 SCRAM,具体根据客户端兼容性配置
connect_timeout = 5000 # 5s
checkout_timeout = 5000 # 5s
idle_timeout = 600000 # 10min
client_idle_timeout = 1800000 # 30min(set 0 for unlimited)
query_timeout = 60000 # 60s
server_lifetime = 86400000 # 24h
# 性能调优(8核)
workers = 6
load_balancing_strategy = "least_active_connections"
prepared_statements = "extended"
# 健康检查
healthcheck_interval = 30000
healthcheck_timeout = 5000
ban_timeout = 60000 # 1min 自动解封
# 日志与监控
log_format = "json"
log_level = "info"
log_connections = true
log_disconnections = true
openmetrics_port = 9090
[admin]
name = "admin"
user = "admin"
password = "your_strong_admin_password"
# === 系统库 ===
[[databases]]
name = "postgres"
host = "127.0.0.1"
port = 5433
role = "primary"
[[databases]]
name = "template1"
host = "127.0.0.1"
port = 5433
role = "primary"
# === 40 个业务库 ===
# 替换 db_biz_NN 为实际库名
[[databases]]
name = "db_biz_01"
host = "127.0.0.1"
port = 5433
role = "primary"
# ... db_biz_02 ~ db_biz_39 ...
[[databases]]
name = "db_biz_40"
host = "127.0.0.1"
port = 5433
role = "primary"
users.toml
# all_databases = true 一条记录覆盖所有数据库
[[users]]
name = "postgres"
all_databases = true
password = "Admin123@" # 明文密码(当前版本 password 字段不支持 SCRAM 哈希)
关键决策理由
| 决策 | 原因 |
|---|---|
default_pool_size = 10 |
1 用户 × 42 库 × 10 = 420 连接,可控 |
min_pool_size = 2 |
42 × 2 = 84 个预热连接,冷启动延迟消除 |
pooler_mode = "transaction" |
绝大多数应用场景最佳选择 |
all_databases = true |
1 条 users 记录,新增库无需改 users.toml |
auth_type = "scram" |
生产环境推荐,安全性更高;trust 仅适用于明确隔离环境 |
workers = 6 |
8 核 × 0.75 |
role = "primary" |
单主库场景必须,role = "auto" 会导致 checkout timeout(见 7.7) |
PG 端配合
-- 理论最大 backend connection:
-- pool_size × user_count × database_count
ALTER SYSTEM SET max_connections = 600; -- 420 + 预留
ALTER SYSTEM SET idle_in_transaction_session_timeout = '10min';
SELECT pg_reload_conf();
注意:
上述公式表示理论最大连接数量,并不代表 pgdog 启动时一定创建全部连接。
实际 PostgreSQL backend connection 数量还受到:
-
min_pool_size
-
当前活跃事务数量
-
实际访问数据库数量
-
连接生命周期策略
影响。
例如:
1 用户 42 数据库 pool_size = 10 理论最大: 1 × 42 × 10 = 420 但是: min_pool_size = 2 初始连接可能: 42 × 2 = 84
因此生产环境不能简单按照理论最大值配置,而应该结合业务峰值压测。
3.2 案例二:读写分离
场景:一主两从,读请求自动路由到副本,写请求路由到主库。
[general]
host = "0.0.0.0"
port = 6432
default_pool_size = 50
pooler_mode = "transaction"
load_balancing_strategy = "least_active_connections" # 最少连接优先
read_write_strategy = "conservative" # 事务级判断
read_write_split = "exclude_primary" # 主库不承担读
# 主库
[[databases]]
name = "prod"
host = "10.0.0.1"
port = 5432
role = "primary"
# 副本 1
[[databases]]
name = "prod"
host = "10.0.0.2"
port = 5432
role = "replica"
# 副本 2
[[databases]]
name = "prod"
host = "10.0.0.3"
port = 5432
role = "replica"
关键:多个
[[databases]]使用相同name,pgdog 自动为name="prod"聚合成一个集群。role决定读写路由。
策略对比:
| read_write_split | 读查询路由 | 适用场景 |
|---|---|---|
include_primary |
主库 + 所有副本 | 主库资源充足 |
exclude_primary |
仅副本 | 主库压力大、写为主 |
prefer_primary |
优先主库,压力大时自动分流到副本 | 保守策略 |
3.3 案例三:自动故障切换
场景:配合 Patroni 等 HA 方案,pgdog 自动感知主备切换。
[general]
# 启用 LSN 检查以自动检测 primary/replica 角色
lsn_check_delay = 0 # 0 = 启动后立即开始 LSN 检查,无延迟
lsn_check_interval = 5000 # 5s
lsn_check_timeout = 5000 # 5s
# 副本延迟超阈值自动封禁
ban_replica_lag = 10000 # 10s 延迟即封禁
ban_replica_lag_bytes = 10485760 # 10MB 延迟即封禁
[[databases]]
name = "prod"
host = "10.0.0.1"
port = 5432
role = "auto" # pgdog 自动检测角色
[[databases]]
name = "prod"
host = "10.0.0.2"
port = 5432
role = "auto"
原理:
role = "auto"时 pgdog 通过pg_is_in_recovery()动态判断节点是 primary 还是 replica,主备切换后自动更新路由。⚠️ 陷阱:role = "auto"必须配合lsn_check_delay = 0使用。如果 LSN 检查被禁用(默认lsn_check_delay = MAX),role = "auto"会导致 checkout timeout。详见 7.7。
3.4 案例四:分片集群
场景:表 orders 按 customer_id 分片到 2 个节点。
[[databases]]
name = "sharded_db"
host = "10.0.0.1"
port = 5432
database_name = "shard_0"
shard = 0
role = "primary"
[[databases]]
name = "sharded_db"
host = "10.0.0.2"
port = 5432
database_name = "shard_1"
shard = 1
role = "primary"
# 分片表定义
[[sharded_tables]]
database = "sharded_db"
name = "orders"
column = "customer_id"
data_type = "bigint"
# 分片映射
[[sharded_tables.mapping]]
values = [1, 2, 3, 4, 5]
shard = 0
[[sharded_tables.mapping]]
values = [6, 7, 8, 9, 10]
shard = 1
对于包含明确分片键条件的简单查询,例如:pgdog 可以根据分片规则计算目标 shard。
注意:
复杂 SQL,例如:
-
JOIN
-
子查询
-
OR 条件
-
IN 查询
-
分片键经过函数计算
需要根据 pgdog 当前版本能力进行验证。
四、运维管理篇
4.1 启动与停止
# 前台启动(调试用)
pgdog --config /etc/pgdog/pgdog.toml --users /etc/pgdog/users.toml run
# 后台启动
nohup pgdog --config /etc/pgdog/pgdog.toml --users /etc/pgdog/users.toml run
> /var/log/pgdog.log 2>&1 &
# 查看进程
ps aux | grep pgdog
# 优雅停止(等待活跃事务完成,默认 60s 超时)
kill -TERM $(pidof pgdog)
# 立即强制停止
kill -KILL $(pidof pgdog)
4.2 systemd 服务管理
Service 文件
# /etc/systemd/system/pgdog.service
[Unit]
Description=pgdog - PostgreSQL Connection Pooler & Proxy
Documentation=https://github.com/pgdogdev/pgdog
After=network-online.target postgresql-15.service
Wants=network-online.target
[Service]
Type=simple
User=root
Group=root
ExecStart=/usr/local/bin/pgdog
--config /etc/pgdog/pgdog.toml
--users /etc/pgdog/users.toml
run
# SIGTERM 优雅停止,给活跃事务 60s 完成
ExecStop=/bin/kill -TERM $MAINPID
TimeoutStopSec=70
# 异常退出自动重启
Restart=on-failure
RestartSec=5s
# 资源限制
LimitNOFILE=65536
LimitNPROC=4096
# 日志接入 journald
StandardOutput=journal
StandardError=journal
SyslogIdentifier=pgdog
Environment="RUST_LOG=info"
[Install]
WantedBy=multi-user.target
- 实际拷机环境中配置如下
[root@openEuler ~/lxm]# cat /etc/systemd/system/pgdog.service
[Unit]
Description=Pgdog PostgreSQL Pool Router
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/pgdog/pgdog --config /usr/local/pgdog/pgdog.toml --users /usr/local/pgdog/users.toml
Restart=on-failure
RestartSec=5
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
常用命令
# 注册与启动
systemctl daemon-reload
systemctl enable pgdog # 开机自启
systemctl start pgdog
# 运维操作
systemctl status pgdog # 查看状态
systemctl stop pgdog # 优雅停止(最多 60s)
systemctl restart pgdog # 重启
# 日志
journalctl -u pgdog -f # 实时跟踪
journalctl -u pgdog -n 100 # 最近 100 行
journalctl -u pgdog --since "10 min ago"
4.3 热重载配置
pgdog 的核心运维优势:绝大多数配置变更无需重启。
支持热重载的参数
| 类别 | 支持热重载 | 需重启 |
|---|---|---|
default_pool_size / min_pool_size |
✅ | — |
pooler_mode |
⚠️ | 涉及连接状态管理,建议低峰验证 |
idle_timeout / query_timeout |
✅ | — |
load_balancing_strategy |
✅ | — |
read_write_split / read_write_strategy |
✅ | — |
ban_timeout / healthcheck_* |
✅ | — |
log_level / log_format |
✅ | — |
新增/修改 [[databases]] 条目 |
⚠️ | 根据版本验证 |
新增/修改 [[users]] 条目 |
⚠️ | 根据版本验证 |
host / port |
❌ | ✅ |
workers |
❌ | ✅ |
tls_* |
❌ | ✅ |
⚠️
pooler_mode虽然支持热重载,但从session切换到transaction(或反之)可能影响已有连接的状态管理,建议在低负载时操作。
热重载流程
# 1. 编辑配置
vim /etc/pgdog/pgdog.toml
# 2. 语法检查(可选但推荐)
pgdog --config /etc/pgdog/pgdog.toml --users /etc/pgdog/users.toml configcheck
# 3. 热重载(不中断服务)
PGPASSWORD=admin_pass psql -h 127.0.0.1 -p 6432 -U admin -d admin -c 'RELOAD;'
# 4. 验证
PGPASSWORD=admin_pass psql -h 127.0.0.1 -p 6432 -U admin -d admin -c 'SHOW pools;'
4.4 Admin 数据库命令详解
连接 Admin 数据库:
PGPASSWORD=<admin_password> psql -h 127.0.0.1 -p 6432 -U admin -d admin
admin 是虚拟数据库,由 pgdog 进程内部实现,不需要在后端 PG 中预先创建。pgdog 识别到 admin 连接后直接在进程内部处理命令,不会转发给后端 PG。
查看状态命令
SHOW pools — 连接池状态(最重要)
-[ RECORD 1 ]--+------------- id | 1 database | db_biz_01 user | postgres addr | 127.0.0.1 role | primary cl_waiting | 0 # 等待获取连接的客户端数 sv_idle | 2 # 空闲后端连接数 sv_active | 3 # 活跃后端连接数 sv_idle_xact | 0 # 空闲事务中的连接数 sv_total | 5 # 后端连接总数 = sv_idle + sv_active + sv_idle_xact maxwait | 0 # 客户端最大等待时间 pool_mode | transaction paused | f # 是否暂停 banned | f # 是否被 ban healthy | t # 是否健康
| 字段 | 说明 |
|---|---|
cl_waiting |
等待获取连接的客户端数(>0 说明池不够用) |
sv_idle |
空闲后端连接数 |
sv_active |
活跃后端连接数 |
sv_idle_xact |
空闲事务中的连接数 |
sv_total |
后端连接总数 = sv_idle + sv_active + sv_idle_xact |
maxwait |
客户端最大等待时间 |
paused |
是否暂停 (PAUSE 命令) |
banned |
是否故障封禁 |
healthy |
健康状态 |
SHOW servers — 后端连接详情
pool_id | database | user | addr | state | transactions | queries ---------+-----------+----------+------------+-------+--------------+--------- 1 | db_biz_01 | postgres | 127.0.0.1 | idle | 3795 | 26481
SHOW stats — 统计信息
database | user | total_xact_count | total_query_count | total_errors | total_wait_time ------------+----------+------------------+-------------------+--------------+----------------- db_biz_01 | postgres | 123456 | 789012 | 0 | 12345
统计字段说明:
-
total_xact_count:总事务数 -
total_query_count:总查询数 -
total_errors:总错误数 -
total_received / total_sent:收发字节数 -
total_xact_time / total_query_time / total_wait_time:事务/查询/等待总耗时
SHOW config — 当前运行时完整配置
管理命令
| 命令 | 说明 | 使用场景 |
|---|---|---|
RELOAD; |
热重载配置文件 | 修改配置后 |
PAUSE postgres; |
暂停某数据库(新请求排队) | 后端 PG 维护 |
RESUME postgres; |
恢复暂停的数据库 | 维护完成 |
MAINTENANCE ON; |
全局维护模式 | 整体维护 |
MAINTENANCE OFF; |
退出维护模式 | 维护完成 |
4.5 连接数精算方法
pgdog 的最大后端连接数为:
MAX_BACKEND = Σ (per_database_pool_size × database_user_count) 下所有 (user,db) 组合
简化公式(所有库用统一 pool_size):
MAX_BACKEND = 用户数 × 数据库数 × default_pool_size PG max_connections ≥ MAX_BACKEND + 50 # 预留运维连接
示例计算:
| 场景 | 计算 | PG max_connections 建议 |
|---|---|---|
| 1用户 × 42库 × 10池 | 420 | 500 |
| 5用户 × 40库 × 15池 | 3,000 | 3,200 |
| 10用户 × 10库 × 20池 | 2,000 | 2,200 |
⚠️ 重要:实际运行中 sv_active 远小于理论最大值。pooler_mode = "transaction" 下,只有同时有活跃事务的连接才会被占用。
4.6 故障排查清单
| 现象 | 排查方法 | 常见原因与解决 |
|---|---|---|
| 客户端连不上 | systemctl status pgdog / ss -tlnp | grep 6432 |
pgdog 未启动或端口被占用 |
| 认证失败 | 检查 auth_type 与 users.toml 密码 |
trust 模式也需 users.toml 定义用户;password 字段必须用明文 |
| "no pool for database" | SHOW pools; |
pgdog.toml 中缺少该 database 的 [[databases]] 条目,或 users.toml 中未定义该用户对该库的访问权限 |
| 连接池耗尽 | SHOW pools; 看 sv_active ≈ sv_total 且 cl_waiting > 0 |
增大 default_pool_size,或增大 PG max_connections |
| 后端数据库异常 | SHOW pools; 看 healthy=f 或 banned=t |
检查后端 PG 状态,ban_timeout 过后自动恢复 |
| 配置未生效 | SHOW config | grep <参数名> |
确认已执行 RELOAD; 或重启 |
| 慢查询占连接 | SHOW pools; 看 sv_active 持续高位 |
设置 query_timeout,定位慢查询 |
| 性能瓶颈 | SHOW stats; 看 total_wait_time 增长 |
增大 workers 或 default_pool_size,考虑分离部署 |
| checkout timeout(写操作) | 检查 role 配置 |
单主库用了 role="auto" 但未启用 LSN 检查(见 7.7) |
五、性能调优篇
5.1 压测数据分析
基于 pgbench TPC-B 同机部署 (8核 aarch64) 的压测结果:
测试环境:
pgbench (客户端) │ ├── 直连测试:pgbench → PostgreSQL (127.0.0.1:5433) │ └── 代理测试:pgbench → pgdog (127.0.0.1:6432) → PostgreSQL (127.0.0.1:5433)
-
pgbench 与 pgdog / PostgreSQL 部署在同一台服务器上(aarch64, 8核)
-
使用 TPC-B 基准测试(
-b tpcb),scale factor = 50,每轮 60 秒
数据汇总:
| 客户端数 | 直连 TPS | pgdog TPS | 比率 | 直连延迟 | 代理延迟 | TPS 损失 |
|---|---|---|---|---|---|---|
| 1 | 633 | 402 | 63.5% | 1.58ms | 2.49ms | 36.5% |
| 4 | 2,077 | 1,516 | 73.0% | 1.93ms | 2.64ms | 27.0% |
| 8 | 3,706 | 2,272 | 61.3% | 2.16ms | 3.52ms | 38.7% |
| 16 | 5,159 | 3,161 | 61.3% | 3.10ms | 5.06ms | 38.7% |
| 32 | 6,285 | 3,780 | 60.1% | 5.09ms | 8.47ms | 39.9% |
| 64 | 7,081 | 3,997 | 56.4% | 9.04ms | 16.01ms | 43.6% |
TPS 趋势图:
TPS 7000 ┤ ● 7081 (直连) │ 6000 ┤ ● 6285 │ 5000 ┤ ● 5159 │ 4000 ┤ ● 3706 ▲ 3997 (代理) │ ▲ 3780 3000 ┤ ● 2077 ▲ 3161 │ ▲ 2272 2000 ┤ ▲ 1516 │ 1000 ┤ ▲ 902 ├───▲────────────────────────────────────────── 0 1 2 4 8 16 32 64 (客户端) ● 直连 PostgreSQL ▲ pgdog 代理
性能开销分析:
-
固定开销:每条请求经过协议解析 → PgQuery AST 解析 → 路由决策 → 连接池调度 → 响应回传
-
低并发 (1~4):固定开销占比高,绝对延迟增量 ~1ms,可接受
-
中并发 (8~32):比率稳定在 60%~61%,线性扩展
-
高并发 (64):pgdog 同机部署时与 PG 竞争 CPU,是主要瓶颈
结论:同机部署引入约 27%~44% 的 TPS 开销,延迟增加约 37%~77%。这是全功能代理的正常开销——pgdog 与 PgBouncer 的定位不同:
PgBouncer 是轻量级 PostgreSQL 连接池,主要解决:
-
客户端连接复用
-
backend connection 数量控制
-
session/transaction pooling
pgdog 在连接池基础上增加 SQL 感知能力,例如:
-
SQL 解析
-
读写分离
-
分片路由
-
查询级流量控制
因此 pgdog 更适合需要数据库流量治理能力的场景。
5.2 配置优化逐项分析
以下基于 42 库实际生产环境(8核 / 7.5GB RAM / pgdog commit f2f2a3d)的运行状态采集,逐项分析配置优化点。
运行状态采集(某时刻快照):
| 指标 | 值 |
|---|---|
| 客户端连接数 | 93 |
| 后端空闲连接数 | 60 |
| 后端活跃连接数 | 0 |
| 等待连接的客户端 | 0(所有池均为 0) |
| PG 实际后端进程数 | 60(全部 idle) |
| query_cache 命中率 | 103 / (103+799) ≈ 11.4% |
PG 错误日志 does not exist |
39 条(prepared statement 相关,无害) |
| pgdog 内存占用 | ~30MB RSS / 485MB VSZ |
问题 1:default_pool_size = 10 过大(🔴 高优先级)
现状:42 个数据库 × 10 连接 = 最多 420 后端连接
问题:
-
实际只有 60 个后端连接在使用,利用率仅 14%(60/420)
-
420 连接 × 每连接约 10MB PG 内存 ≈ 4.2GB,加上 shared_buffers 512MB,接近物理内存
-
PG
max_connections = 1000,420 已占 42%
优化建议:
# 方案 A:统一降低(推荐)
default_pool_size = 5
# 方案 B:按库差异化配置(更精细)
[[databases]]
name = "foundation"
host = "127.0.0.1"
port = 54321
role = "primary"
pool_size = 10 # 高频库保持 10
[[databases]]
name = "ras"
host = "127.0.0.1"
port = 54321
role = "primary"
pool_size = 8 # 次高频库
预期效果:方案 A 降至 42 × 5 = 210 后端连接,节省 50%。
问题 2:min_pool_size = 0 无预热(🟡 中优先级)
首次请求需新建连接,SCRAM-SHA-256 认证需 3 次网络往返,冷启动延迟约 50ms。
min_pool_size = 2 # 全局默认预热 2 个连接
注意:42 库 × 2 = 84 个预热连接,需确保 PG
max_connections足够。
问题 3:healthcheck_interval = 300000(5分钟)过长(🟡 中优先级)
PG 宕机后最长需 5 分钟才能检测到。
healthcheck_interval = 30000 # 30 秒检查一次
问题 4:idle_timeout = 600000(10分钟)偏长(🟡 中优先级)
空闲连接占用 PG 资源,配合 min_pool_size = 2 可缩短回收时间。
idle_timeout = 300000 # 空闲 5 分钟回收
问题 5:query_timeout = 300000(5分钟)过长(🟡 中优先级)
OLTP 场景下 5 分钟的查询通常是异常,慢查询长时间占用连接可能导致池耗尽。
query_timeout = 60000 # OLTP 场景建议 60 秒
问题 6:checkout_timeout = 5000(5秒)可能不够(🟢 低优先级)
高并发场景可适当增加:
checkout_timeout = 10000 # 10 秒
问题 7:log_connections = true + log_disconnections = true 日志量大(🟢 低优先级)
生产环境稳定后可关闭:
log_connections = false
log_disconnections = false
问题 8:query_cache 命中率低(11.4%)(🟢 低优先级,预期行为)
prepared_statements = "extended" 模式下,pgdog 的查询缓存与 prepared statement 机制重叠。在单主库 + 无分片场景下,query_cache 价值有限,低命中率是正常的。如需节省内存可设置 query_cache_limit = 0。
PG 侧优化
# postgresql.conf 优化建议
# pgdog 最大后端连接数 × 1.5(含管理连接、健康检查等余量)
max_connections = 400 # 原 1000 → 400,配合 pgdog 连接池
5.3 参数调优建议
| 参数 | 默认值 | 推荐值 | 原因 |
|---|---|---|---|
workers |
2 | CPU核数 × 0.5~1 | 充分利用多核。8核 → 4~8 |
default_pool_size |
10 | 5~50 | 多库场景建议 5,单库可 50 |
min_pool_size |
1 | 2~5 | 消除冷启动延迟 |
pooler_mode |
transaction | transaction | 绝大多数场景 |
prepared_statements |
extended | extended | 兼容大多数 ORM/驱动 |
load_balancing_strategy |
random | least_active_connections | 多副本时更均匀 |
idle_timeout |
60s | 300s~600s | 配合 min_pool_size,减少频繁建连/断连 |
connect_timeout |
5s | 5s | 默认合理 |
checkout_timeout |
5s | 5~10s | 高并发时给客户端更多等待时间 |
query_timeout |
无限 | 60~300s | 防止慢查询占连接 |
server_lifetime |
24h | 1~24h | 防止连接老化,配合 jitter |
connect_attempts |
1 | 2~3 | 提高连接建连成功率 |
healthcheck_interval |
30s | 30s | 故障检测及时,开销可控 |
独立部署 vs 同机部署:
如果 TPS 是关键指标且 pgdog 不是必需的(不需要读写分离/分片),考虑:
-
将 pgdog 部署到独立服务器(消除 CPU 争用)
-
如果只需要纯连接池,可评估 PgBouncer
5.4 监控指标说明
Prometheus 端点:http://<pgdog_host>:9090/metrics
关键指标:
| 指标 | 说明 | 告警阈值建议 |
|---|---|---|
pgdog_pool_waiting |
等待连接的客户端数 | > 10 |
pgdog_pool_active |
活跃后端连接数 | > pool_size × 0.9 |
pgdog_pool_banned |
被封禁的池 | > 0 |
pgdog_errors_total |
总错误数 | 速率突增 |
pgdog_wait_time |
等待时间 | > 100ms |
Admin 命令日常巡检:
#!/bin/bash
# 日常巡检脚本
ADMIN_PASS="your_password"
echo "=== 连接池高水位 ==="
PGPASSWORD=$ADMIN_PASS psql -h 127.0.0.1 -p 6432 -U admin -d admin -c "SHOW pools;" |
awk -F'|' 'NR>2 && NF>1 {print}'
echo "=== 被封禁的池 ==="
PGPASSWORD=$ADMIN_PASS psql -h 127.0.0.1 -p 6432 -U admin -d admin -c "SHOW pools;" |
grep -i "t"
echo "=== 错误统计 ==="
PGPASSWORD=$ADMIN_PASS psql -h 127.0.0.1 -p 6432 -U admin -d admin -c "SHOW stats;"
5.5 Prometheus 告警建议
基于 openmetrics_port = 9090,建议配置以下告警:
# pgdog 后端连接使用率 > 80%
- alert: PgdogPoolNearExhaustion
expr: pgdog_pool_active / pgdog_pool_size > 0.8
for: 5m
# 客户端等待连接
- alert: PgdogClientWaiting
expr: pgdog_pool_waiting > 0
for: 1m
# 被封禁的池
- alert: PgdogPoolBanned
expr: pgdog_pool_banned > 0
for: 1m
六、编译安装篇
6.1 源码编译
# 1. 获取源码
git clone https://github.com/pgdogdev/pgdog.git
cd pgdog
# 2. 配置 Cargo 国内镜像(可选,国内加速)
mkdir -p ~/.cargo
cat >> ~/.cargo/config.toml << 'EOF'
[source.crates-io]
replace-with = 'ustc'
[source.ustc]
registry = "sparse+https://mirrors.ustc.edu.cn/crates.io-index/"
[registries.crates-io]
protocol = "sparse"
[http]
multiplexing = false
EOF
# 3. aarch64 环境需删除 x86_64 专用 linker 配置
sed -i '/[target.x86_64-unknown-linux-gnu]/,/mold"]/d' .cargo/config.toml
# 4. 编译
cargo build --release
# 5. 安装
cp target/release/pgdog /usr/local/bin/pgdog
chmod +x /usr/local/bin/pgdog
# 6. 创建配置目录
mkdir -p /etc/pgdog
# 7. 验证
pgdog --version
关键配置说明:
6.2 相关文件总览
编译安装完成后,pgdog 相关文件分布在以下位置:
| 路径 | 说明 | 大小 |
|---|---|---|
/usr/local/bin/pgdog |
可执行文件 | 31 MB |
/etc/pgdog/pgdog.toml |
代理主配置文件 | — |
/etc/pgdog/users.toml |
用户认证配置文件 | — |
/etc/systemd/system/pgdog.service |
systemd 服务文件 | — |
/build/pgdog/ |
源码目录 | — |
/build/pgdog/target/release/pgdog |
编译产物 | 31 MB |
/root/.cargo/config.toml |
Cargo 全局配置(镜像源等) | — |
6.3 常见问题
| 问题 | 原因 | 解决 |
|---|---|---|
GLIBC_2.38/2.39 not found |
预编译二进制 glibc 版本过高 | 在目标机器上源码重新编译(切勿升级系统 glibc) |
| Cargo HTTPS 下载 crate 失败 | HTTP/2 多路复用在部分网络不稳定 | 配置国内镜像 + http.multiplexing = false |
trust 模式认证失败 |
pgdog 即使 auth_type="trust" 仍需 users.toml 定义用户 |
添加 [[users]] 条目,password 可为占位符 |
| admin 密码未设置被随机生成 | 不设置则自动生成 _pgdog_XXXX |
显式设置 [admin].password,debug 模式下日志会打印 |
七、踩坑实录与常见陷阱
以下问题均在 openEuler 22.03 LTS-SP4 (aarch64) 环境实战中遇到,记录根因与解决方案,避免二次踩坑。
7.1 超时参数不支持时间单位字符串
现象:
ERROR failed to load pgdog.toml: invalid type: string "5s", expected u64, line 43 Error: MissingField("invalid type: string "5s", expected u64", 43)
根因:pgdog 的超时参数类型为 u64(毫秒整数),不支持 "5s" / "10m" / "1h" 等字符串格式。这与 PgBouncer 的配置习惯不同,容易踩坑。
修正方法:
| 参数 | 错误写法 | 正确写法 | 换算 |
|---|---|---|---|
connect_timeout |
"5s" |
5000 |
5秒 × 1000 |
checkout_timeout |
"5s" |
5000 |
5秒 × 1000 |
idle_timeout |
"10m" |
600000 |
10分钟 × 60 × 1000 |
client_idle_timeout |
"30m" |
1800000 |
30分钟 × 60 × 1000 |
query_timeout |
"300s" |
300000 |
300秒 × 1000 |
healthcheck_interval |
"30s" |
30000 |
30秒 × 1000 |
healthcheck_timeout |
"5s" |
5000 |
5秒 × 1000 |
ban_timeout |
"1m" |
60000 |
1分钟 × 60 × 1000 |
建议:注释中标注原始值(如 # 原 5s),方便后续维护理解含义。
7.2 psql 默认走 Unix socket 导致连不上 pgdog
现象:
psql -U postgres -d postgres -p 6432 psql: error: connection to server on socket "/tmp/.s.PGSQL.6432" failed: No such file or directory
根因:pgdog 监听的是 TCP 端口 0.0.0.0:6432,不创建 Unix socket 文件。而 psql 不指定 -h 时默认使用 Unix socket 连接。
解决:必须加 -h 参数强制走 TCP:
# 正确
psql -U postgres -d postgres -h 127.0.0.1 -p 6432
# 或
psql -U postgres -d postgres -h localhost -p 6432
# 错误(走 Unix socket,连不上)
psql -U postgres -d postgres -p 6432
7.3 users.toml 的 password 字段必须用明文密码
现象:
FATAL: password for user "postgres" and database "postgres" is wrong, or the database does not exist
根因:从 pg_authid.rolpassword 复制 SCRAM-SHA-256 哈希值放入 users.toml 的 password 字段,pgdog 无法正确使用。虽然哈希值与 PG 中一致,但 pgdog 的 password 字段需要明文密码来参与 SCRAM 握手(客户端→pgdog 和 pgdog→后端PG 两段认证都需要明文)。
正确做法:
# users.toml — 正确:用明文密码
[[users]]
name = "postgres"
all_databases = true
password = "Admin123@"
# users.toml — 错误:不能用 pg_authid 中的 SCRAM 哈希
[[users]]
name = "postgres"
all_databases = true
password = "SCRAM-SHA-256$4096:JquNCpGbfTQJJbVVa+ARwQ==$0CVeobl1n9jqcmo3MiamoTCHsnuPxwQAl3LlrdEeMwY=:LK8dMwZwMlwM28Fmqror/eQuXqs0rcuxh38DNmRITLw="
7.4 [admin] 段的 password 也必须用明文
现象:
psql -U admin -d admin -p 6432 -h 127.0.0.1 FATAL: password for user "admin" and database "admin" is wrong, or the database does not exist
根因:与 7.3 相同,[admin].password 也不支持 SCRAM 哈希格式,必须用明文。
正确做法:
[admin]
name = "admin"
user = "admin"
password = "Admin_147@" # 明文密码,不能用 SCRAM 哈希
7.5 SHOW POOLS 等管理命令必须在 admin 库执行
现象:
postgres=# SHOW pools; FATAL: checkout timeout server closed the connection unexpectedly
根因:SHOW pools / SHOW servers / RELOAD 等是 pgdog Admin 管理数据库的命令,不是标准 SQL。在业务库(如 postgres)中执行时,pgdog 会把它当成普通 SQL 转发给后端 PG,后端 PG 不认识这个命令,同时 transaction 模式下的连接复用机制会导致 checkout timeout。
正确做法:
# 连接 admin 虚拟数据库执行管理命令
PGPASSWORD=Admin_147@ psql -U admin -d admin -p 6432 -h 127.0.0.1 -c "SHOW pools;"
# 交互式
PGPASSWORD=Admin_147@ psql -U admin -d admin -p 6432 -h 127.0.0.1
admin=# SHOW pools;
admin=# SHOW servers;
admin=# SHOW stats;
admin=# RELOAD;
7.6 pgdog.toml 与 users.toml 中的 admin 用户是两套体系
结论:不需要两处都配 admin 用户。
| 配置位置 | 认证方向 | 用途 |
|---|---|---|
pgdog.toml [admin] 段 |
客户端 → pgdog(管理库) | 连接 admin 虚拟数据库,执行管理命令 |
users.toml [[users]] |
客户端 → pgdog(业务库) | 连接业务数据库,执行普通 SQL |
典型配置:
# pgdog.toml — 管理库认证
[admin]
name = "admin"
user = "admin"
password = "Admin_147@"
# users.toml — 业务库认证
[[users]]
name = "postgres"
all_databases = true
password = "Admin123@"
特殊情况:只有当需要用 admin 用户通过 pgdog 连接后端 PG 的业务库时,才需要在 users.toml 中也加一条 admin 的 [[users]]。但这和 [admin] 段是两回事。
7.7 role=“auto” + LSN 检查禁用导致 checkout timeout(最关键陷阱)
现象:
Go 程序(bdatabase + pgx)通过 pgdog 连接 PG,SELECT 正常,INSERT/UPDATE/DELETE/CREATE TABLE 报 checkout timeout。psql 命令行一切正常。
FATAL: checkout timeout (SQLSTATE 58000)
根因:
[[databases]] 中 role = "auto" 配合 lsn_check_delay = MAX(默认禁用),导致 pgdog 的自动角色检测被禁用。此时 pgdog 无法确定后端是 primary 还是 replica,连接池行为异常——写操作无法获取连接。
pgdog 启动时会输出 WARN 日志(容易被忽略):
WARN database "xxx" has a role set to "auto" but LSN checks are disabled: this disables automatic role detection
实验矩阵:
| 配置 | 结果 | 说明 |
|---|---|---|
| 1库 + transaction + extended + role=primary | ✅ 8/8 | 基准通过 |
| 2库 + transaction + extended + role=primary | ✅ 8/8 | 多库无影响 |
| 10库 + transaction + extended + role=primary | ✅ 8/8 | 多库无影响 |
| 42库 + transaction + extended + role=primary | ✅ 8/8 | 多库无影响 |
| 42库 + transaction + extended + role=auto | ❌ 4/8 | checkout timeout |
| 42库 + session + extended + role=auto | ✅ 8/8 | session 模式绕过了问题 |
关键结论:
-
**role = "auto"**不是"自动检测"的万能配置,它需要 LSN 检查机制配合才能工作 -
单主库无副本场景,必须用
**role = "primary"**,不能用role = "auto" -
只有在配合 Patroni 等高可用方案、且正确配置了
lsn_check_delay = 0时,才应使用role = "auto"
解决:
# 单主库场景 — 必须用 primary
[[databases]]
name = "test"
host = "127.0.0.1"
port = 54321
role = "primary" # ✅ 正确
# 错误:auto 需要配合 LSN 检查
# role = "auto" # ⚠️ 需要配合角色检测配置
如果确实需要 auto 角色,必须同时配置 LSN 检查:
[general]
lsn_check_delay = 0 # 0 = 启用自动角色检测
lsn_check_interval = 5000 # 5s 检查一次
lsn_check_timeout = 5000 # 5s 超时
7.8 transaction 模式下 PG 日志出现 prepared statement does not exist 错误
现象:
Go 程序(bdatabase + pgx)通过 pgdog transaction 模式连接 PG,业务功能全部正常(8/8 通过),但 PG 错误日志中出现大量:
ERROR: prepared statement "pgx_0" does not exist STATEMENT: deallocate "pgx_0" ERROR: prepared statement "pgx_1" does not exist STATEMENT: deallocate "pgx_1"
验证数据(42 库 + transaction + extended + role=primary):
-
Go 测试结果:8/8 PASS,全部功能正常
-
PG 错误日志统计:13 条
does not exist错误,涉及pgx_0~pgx_4 -
无其他类型错误
根因:
这是 transaction 模式 + prepared statements 的已知行为,属于无害错误:
-
事务结束时,pgdog 对后端连接执行
DISCARD ALL,该命令会 隐式清除所有 prepared statements(等效于DEALLOCATE ALL) -
连接归还到池后,pgx 驱动在下次使用该连接时,发现本地缓存的 statement 名已不存在于服务端,会尝试
DEALLOCATE "pgx_N"来清理本地缓存 -
但服务端的 statement 已被
DISCARD ALL清除,因此DEALLOCATE报错does not exist -
pgx 驱动会 忽略此错误,重新
PREPARE该 statement,后续操作正常
时序图:
Client (pgx) pgdog PostgreSQL | | | |--- COMMIT ------->| | | |--- DISCARD ALL -->| ← 清除所有 prepared statements | |<-- ReadyForQuery -| | [连接归还到池] | | | | | |--- 下次请求 ------>| | | |--- DEALLOCATE ----> ← pgx 尝试清理旧 statement | |<-- ERROR: does not exist ← 无害错误 | |--- PREPARE ------->| ← pgx 重新创建 statement | |<-- ParseComplete --| | |--- BIND/EXECUTE -->| ← 正常执行
影响评估:
| 维度 | 评估 |
|---|---|
| 业务功能 | ✅ 无影响,所有操作正常完成 |
| 数据一致性 | ✅ 无影响 |
| 性能 | ⚠️ 轻微影响:每次连接复用后首次使用 statement 需重新 PREPARE,增加一次网络往返 |
| 日志噪音 | ⚠️ PG 错误日志会产生噪音,可能干扰问题排查 |
| 连接安全 | ✅ 无影响,pgdog 的 DISCARD ALL 是正确行为 |
缓解措施(可选):
-
降低日志噪音:在
postgresql.conf中配置log_min_messages = WARNING(默认已是此值,ERROR 级别日志仍会记录) -
pgx 驱动侧:设置
statement_cache_capacity = 0可完全禁用 prepared statement 缓存(但会失去 prepared statement 的性能优势) -
接受现状:这是 transaction 模式下 prepared statement 的固有行为,pgdog 和 pgx 都在正确处理
关键结论:此错误 不需要修复,只有当此错误伴随业务功能异常时,才需要进一步排查。
7.9 pgdog hash 生成的密码与 pg_authid 中不同
现象:
# PG 中创建用户
postgres=# create user admin with password 'Admin_147@';
postgres=# select rolpassword from pg_authid where rolname='admin';
# 输出: SCRAM-SHA-256$4096:NvGQj6TWWFos1SzGhyopvw==$gWRHZK1JSDh0zNMZ98K9aj0CE2DaE607Ee53pkDbhAU=:YRYwEGDGzkZVKCM2MVVscjUrYjkfEySiGLLqPFTCi70=
# pgdog hash 生成
pgdog hash Admin_147@
# 输出: SCRAM-SHA-256$4096:Nabo9Vs8BYgg6iEIZl/J6w==$ANIj3dAKyQb7NZ5SVPs5dxpH5Rq8XmwFJ/BEq9PsSJQ=:lmsaLR2APCeGt6eKC3panMmP7LiBYO1FbcN26Zfz9zo=
两者不同,但都能验证同一个明文密码。
根因:SCRAM-SHA-256 的密码哈希包含一个随机 salt,每次计算时 salt 不同,最终哈希值就不同。
SCRAM-SHA-256$4096:Nabo9Vs8BYgg6iEIZl/J6w==$ANIj3dAKyQb7NZ5SVPs5dxpH5Rq8XmwFJ/BEq9PsSJQ=:... ↑迭代次数 ↑salt(随机) ↑StoredKey(由salt+密码派生)
-
PostgreSQL
create user时:生成随机 salt A → 计算出哈希值 X -
pgdog
hash时:生成随机 salt B → 计算出哈希值 Y
salt 不同 → 哈希值不同,但都能用来验证同一个密码。
pgdog hash 的用途:生成 SCRAM-SHA-256 哈希供 pgdog 配置文件使用,但当前版本 **password** 字段只支持明文,不支持哈希格式。
7.10 踩坑速查表
| 现象 | 根因 | 解决 |
|---|---|---|
invalid type: string "5s", expected u64 |
超时参数不支持时间单位字符串 | 改为毫秒整数,如 5000 |
No such file or directory (socket) |
psql 默认走 Unix socket | 加 -h 127.0.0.1 |
password ... is wrong (业务库) |
users.toml 用了 SCRAM 哈希 | 改为明文密码 |
password ... is wrong (admin 库) |
[admin].password 用了 SCRAM 哈希 | 改为明文密码 |
checkout timeout (show pools) |
管理命令在业务库执行 | 连接 admin 库执行 |
| admin 库连不上 | 不了解 admin 是虚拟库 | 不需要创建,直接连 |
**checkout timeout**(写操作) |
role=“auto” + LSN 检查禁用 | 单主库用 role="primary" |
PG 日志 prepared statement "pgx_N" does not exist |
transaction 模式下 DISCARD ALL + pgx 驱动的已知行为 |
无害错误,不影响业务(见 7.8) |
八、命令行工具
8.1 子命令概览
pgdog [OPTIONS] [COMMAND]
| 命令 | 说明 |
|---|---|
run |
启动 pgdog 代理服务 |
hash |
生成 SCRAM-SHA-256 密码哈希(注意:当前 users.toml 的 password 字段只支持明文) |
route |
测试查询路由(离线分析 SQL 会被路由到哪个分片/节点) |
configcheck |
检查配置文件语法 |
data-sync |
使用逻辑复制同步数据 |
schema-sync |
同步数据库 schema |
setup |
为分片集群执行必要的配置步骤 |
help |
帮助信息 |
8.2 常用命令示例
# 1. 生成密码哈希
pgdog hash "mypassword"
# 2. 检查配置
pgdog --config /etc/pgdog/pgdog.toml --users /etc/pgdog/users.toml configcheck
# 3. 测试查询路由
echo "SELECT * FROM users WHERE id = 1;" > /tmp/test.sql
pgdog --config /etc/pgdog/pgdog.toml --users /etc/pgdog/users.toml
route --user postgres --database postgres --file /tmp/test.sql
# 4. 分片集群初始化
pgdog --config /etc/pgdog/pgdog.toml setup --database sharded_db
8.3 客户端连接方式
# psql 连接
PGPASSWORD=postgres psql -h 127.0.0.1 -p 6432 -U postgres -d postgres
# 应用程序连接串
# postgresql://postgres:postgres@127.0.0.1:6432/postgres
# pgbench 压测
pgbench -h 127.0.0.1 -p 6432 -U postgres -d postgres -T 60 -c 10 -j 10
注意:客户端连接 pgdog 与直连 PostgreSQL 的唯一区别是端口号(6432 vs 5432/5433),其他参数完全相同。务必加
-h参数强制走 TCP。
附录
A. 配置文件模板位置
| 文件 | 路径 | 说明 |
|---|---|---|
| 可执行文件 | /usr/local/bin/pgdog |
pgdog 二进制 |
| 主配置 | /etc/pgdog/pgdog.toml |
代理配置 |
| 用户配置 | /etc/pgdog/users.toml |
用户认证 |
| systemd | /etc/systemd/system/pgdog.service |
服务管理 |
| 源码 | /build/pgdog/ |
源码目录 |
| 编译产物 | /build/pgdog/target/release/pgdog |
release 编译产物 |
| Cargo 配置 | /root/.cargo/config.toml |
Rust 镜像源等 |
B. 环境变量覆盖
pgdog 支持通过环境变量覆盖部分配置项。
具体支持范围取决于当前版本实现。
生产环境建议:
-
稳定配置使用 TOML 文件管理
-
容器环境使用环境变量覆盖部署相关参数
-
发布前验证目标版本支持的配置映射
export PGDOG_HOST=0.0.0.0
export PGDOG_PORT=6432
export PGDOG_WORKERS=4
export PGDOG_DEFAULT_POOL_SIZE=10
export PGDOG_MIN_POOL_SIZE=2
export PGDOG_POOLER_MODE=transaction
export PGDOG_AUTH_TYPE=scram
export PGDOG_CONNECT_TIMEOUT=5000
export PGDOG_HEALTHCHECK_INTERVAL=30000
export PGDOG_LOG_LEVEL=debug
export PGDOG_LOG_FORMAT=json
export PGDOG_OPENMETRICS_PORT=9090
export PGDOG_ADMIN_PASSWORD=my_admin_pass
注意:并非所有配置项都支持环境变量覆盖,复杂类型(枚举、Option、Vec 等)可能不支持。
C. 快速运维命令速查
| 操作 | 命令 |
|---|---|
| 启动 | systemctl start pgdog |
| 停止 | systemctl stop pgdog |
| 重启 | systemctl restart pgdog |
| 开机自启 | systemctl enable pgdog |
| 查看状态 | systemctl status pgdog |
| 实时日志 | journalctl -u pgdog -f |
| 语法检查 | pgdog --config ... --users ... configcheck |
| 热重载 | psql -h ... -p 6432 -U admin -d admin -c 'RELOAD;' |
| 查看连接池 | 同上 -c 'SHOW pools;' |
| 查看服务器 | 同上 -c 'SHOW servers;' |
| 查看统计 | 同上 -c 'SHOW stats;' |
| 暂停某库 | 同上 -c 'PAUSE db_name;' |
| 维护模式 | 同上 -c 'MAINTENANCE ON;' |
| 生成密码哈希 | pgdog hash "password" |
| 测试路由 | pgdog route --user postgres --database postgres --file /tmp/test.sql |
D. 一键压测脚本
#!/bin/bash
# pgbench 对比压测脚本
RESULT_FILE="/tmp/bench_results.txt"
CLIENTS="1 4 8 16 32 64"
T_DURATION=60
echo "====== 直连压测 ======" | tee $RESULT_FILE
for c in $CLIENTS; do
echo "--- 客户端: $c (T=${T_DURATION}s) ---" | tee -a $RESULT_FILE
pgbench -h 127.0.0.1 -p 5433 -U postgres -d postgres
-T $T_DURATION -c $c -j $c 2>&1 | tee -a $RESULT_FILE
sleep 2
done
echo "" | tee -a $RESULT_FILE
echo "====== pgdog 代理压测 ======" | tee -a $RESULT_FILE
for c in $CLIENTS; do
echo "--- 客户端: $c (T=${T_DURATION}s) ---" | tee -a $RESULT_FILE
pgbench -h 127.0.0.1 -p 6432 -U postgres -d postgres
-T $T_DURATION -c $c -j $c 2>&1 | tee -a $RESULT_FILE
sleep 2
done
echo "压测完成,结果保存在 $RESULT_FILE"
E. 优化后推荐配置
pgdog.toml 优化版(以下配置不一定符合实际场景, 还是需根据实际情况酌情修改适配)
[general]
host = "0.0.0.0"
port = 6432
# ===== 连接池核心参数(已优化) =====
default_pool_size = 5 # 原 10 → 5,降低后端连接总数
min_pool_size = 0 # 原 0 → 2,预热减少冷启动延迟
pooler_mode = "transaction"
# ===== 认证 =====
auth_type = "scram"
# ===== 超时控制(已优化) =====
connect_timeout = 5000
checkout_timeout = 10000 # 原 5000 → 10000,高并发时更从容
idle_timeout = 300000 # 原 600000 → 300000,空闲 5 分钟回收
client_idle_timeout = 1800000
query_timeout = 60000 # 原 300000 → 60000,OLTP 场景 60 秒足够
# ===== 性能调优 =====
workers = 6
load_balancing_strategy = "least_active_connections"
prepared_statements = "extended"
# ===== 健康检查(已优化) =====
healthcheck_interval = 30000 # 原 300000 → 30000,30 秒检查一次
healthcheck_timeout = 5000
ban_timeout = 60000
# ===== 日志与监控(已优化) =====
log_level = "info"
log_format = "json"
log_connections = false # 原 true → false,减少日志量
log_disconnections = false # 原 true → false,减少日志量
openmetrics_port = 9090
[admin]
name = "admin"
user = "admin"
password = "Admin_147@"
# ===== 高频库单独配置 =====
[[databases]]
name = "foundation"
host = "127.0.0.1"
port = 54321
role = "primary"
pool_size = 10 # foundation 保持 10 连接
min_pool_size = 3 # 预热 3 个
[[databases]]
name = "ras"
host = "127.0.0.1"
port = 54321
role = "primary"
pool_size = 8
min_pool_size = 2
# ===== 系统默认库 =====
[[databases]]
name = "postgres"
host = "127.0.0.1"
port = 54321
role = "primary"
[[databases]]
name = "template1"
host = "127.0.0.1"
port = 54321
role = "primary"
# ===== 其余业务库使用 default_pool_size=5 =====
# (配置同现有,省略)
PostgreSQL 侧建议
# postgresql.conf 优化建议
max_connections = 400 # 原 1000 → 400,配合 pgdog 连接池
shared_buffers = 512MB # 保持不变
work_mem = 4MB # 保持不变
effective_cache_size = 2GB # 保持不变
优化效果预估
| 指标 | 优化前 | 优化后(预估) | 改善 |
|---|---|---|---|
| 最大后端连接数 | 420 | ~200(含高频库 10+8) | -52% |
| PG 内存占用(连接) | ~600MB(60×10MB) | ~200MB(20×10MB,idle 回收后) | -67% |
| 冷启动首次请求延迟 | ~50ms(新建连接+SCRAM) | ~5ms(预热连接就绪) | -90% |
| 故障检测时间 | 最长 5 分钟 | 最长 30 秒 | -90% |
| 慢查询占坑时间 | 最长 5 分钟 | 最长 60 秒 | -80% |
| 日志 I/O | 高(连接/断开全记录) | 低 | -80% |
变更风险评估
| 变更项 | 风险等级 | 说明 | 回滚方案 |
|---|---|---|---|
default_pool_size 10→5 |
🟡 中 | 高并发时可能 checkout_timeout | 改回 10 |
min_pool_size 0→2 |
🟢 低 | 增加预热连接,内存略增 | 改回 0 |
healthcheck_interval 5m→30s |
🟢 低 | 增加健康检查频率,PG 负载微增 | 改回 300000 |
idle_timeout 10m→5m |
🟢 低 | 空闲连接更快回收 | 改回 600000 |
query_timeout 5m→60s |
🟡 中 | 如有长查询会被杀 | 改回 300000 |
checkout_timeout 5s→10s |
🟢 低 | 等待更久,减少超时错误 | 改回 5000 |
log_connections/disconnections |
🟢 低 | 不影响功能 | 改回 true |
PG max_connections 1000→400 |
🟡 中 | 需重启 PG | 改回 1000 |
实施步骤
-
先调 pgdog 配置(无需重启 PG,reload pgdog 即可)
# 备份当前配置 cp /etc/pgdog/pgdog.toml /etc/pgdog/pgdog.toml.bak # 修改配置后 reload PGPASSWORD=Admin_147@ psql -h 127.0.0.1 -p 6432 -U admin -d admin -c 'RELOAD;' # 或重启 pgdog systemctl restart pgdog -
观察 1~2 小时,通过 Prometheus 监控关注:
-
sv_active:活跃连接数是否正常 -
cl_waiting:是否有客户端等待连接 -
checkout_timeout错误是否增加
-
-
确认稳定后,再调整 PG
max_connections(需重启 PG,需维护窗口)




