22.5 连接预算与过载边界
连接治理的目标不是让所有请求最终都能排到数据库,而是:
这需要同时预算 connection、active transaction、queue length、等待时间和
重试。只设置一个 max_connections 没有形成过载边界。
22.5.1 按服务分配连接、并发与队列
先分服务,再分数字
一个数据库集群常同时承担:
它们的价值、服务时间和失败策略不同。共享一个 pool 意味着:
按服务分配至少包括:
| 维度 | 问题 |
|---|---|
| client connections | 应用能保持多少逻辑连接 |
| server connections | 最多占多少 PostgreSQL backend |
| active concurrency | 同时执行多少事务/查询 |
| queue length/time | 多久后拒绝,最多积压多少 |
| resource | CPU、I/O、work_mem、temp、lock |
| priority | 过载时谁先被削减 |
| reserve | 谁能在拥塞时进入控制面 |
connection budget 不是 concurrency budget
transaction pool 可以有:
三者都合理,只要:
- client process/FD/TLS 成本可承受;
- server pool 不超过数据库预算;
- active workload 经压测;
- 960 个等待者不会无限停留;
- deadline 和拒绝策略有效。
把所有实例相加
预算必须按全局 deployment:
例如:
若 PgBouncer server pool 是 32,客户端能排队;若直连,则一次 blue/green 发布就可能把 backend 翻倍。
database/user pair 的隔离
PgBouncer pool key 通常包含 database 与 user。可以用:
建立不同预算与权限。
不要无界创建 role:
即使每个 pair 很小,乘法也可能超过 PostgreSQL。可通过:
max_db_connections;max_user_connections;- per-database/user override;
- group role + application context;
- tenant 分片;
- idle pool cleanup;
控制。
负载并发门槛
连接池限制的是 backend 数,不直接限制一条连接里 query 的资源。还需要:
- application concurrency semaphore;
- job worker count;
- query governor;
- statement timeout;
- role/database resource policy;
- workload isolation/offline replica。
例如 8 条并行 hash join 可能比 32 条短索引查询更重。server pool size 要按 workload mix 压测。
queue 的接受条件
定义:
长期稳定至少要求:
否则任何有限 queue 最终都会满。
短 burst 的近似吸收能力:
这不是精确 queueing model,但迫使团队问“burst 多大、持续多久”,而不是把 max queue 随手设成 10,000。
Pigsty/HAProxy/PgBouncer 三处上限
本章渲染配置含:
大数字不表示应使用到它。真正的有效边界是这些限制、活跃 pair 和所有实例 总和的组合。
如果 HAProxy 允许 5000、PgBouncer 允许 20000,而应用 deadline 2 秒, 仍应在更早层用 application concurrency/query wait timeout 拒绝过期工作。
一份分配账本
headroom 不是浪费,而是吸收估算误差、maintenance 和 incident action。
22.5.2 超时层级、取消传播与熔断
一次请求经过多个时钟
若各自独立设置,会出现:
资源在用户离开后继续消耗。
deadline budget
把请求总预算 分解:
各层不一定串行,有些重叠;这个式子是设计账本,不是精确 profiler。
例如 2 秒交互请求:
PgBouncer query_wait_timeout=120s 显然不匹配该请求。可以按服务 override,
或让应用 acquire/overall deadline 更早终止并正确 cancel。
connect timeout 不是 failover timeout
多 host 串行尝试时:
[ T_{\text{connect worst}} \approx \sum_{\text{host}} T_{\text{connect host}}
- DNS/TLS/backoff ]
三个 host × 5 秒可能已经超过 request deadline。驱动是否并行尝试、每 host 还是全局 timeout,要按版本确认。
statement_timeout
PostgreSQL 从收到命令开始计时;达到后取消当前 statement。它不一定包含:
- 应用 pool 等待;
- PgBouncer queue;
- DNS/TCP/TLS;
- 客户端处理结果;
- 上一次 idle transaction。
按 role/database 设置比一个全局值更实用:
事务级可以:
lock_timeout
它只限制等待 lock 的时间,不限制 query 总执行时间。
DDL/migration 常用:
意图是:
不要把 lock timeout 设置得比 statement timeout 更长而期待它生效。
idle transaction timeout
切断已开始事务但长期不发 query 的 session。它是 vacuum/lock 保护,不应拿来 清理普通 idle pool connection。
还有普通 idle_session_timeout,但连接池可能把 idle connection 视为资产;
使用前要评估 reconnect churn 和 middleware 兼容。
取消传播
客户端取消 PostgreSQL query 通常需要单独 cancel request/connection path。 经过 pool/proxy 时要验证:
- cancel 能定位正确 backend;
- client 已换 backend 后不会 cancel 别人;
- proxy 是否转发;
- timeout 后 transaction 是否处于 aborted;
- connection 是否应丢弃;
- server query 是否确实停止。
不能只看到 HTTP 499/timeout 就认为数据库工作结束。
熔断器
breaker 保护的是下游与自身:
触发信号应比“任意 SQL error”精细:
- pool acquire timeout;
- connection/role check failure;
- sustained queue;
- downstream saturation;
- known infrastructure outage。
不要因业务约束错误、syntax error 或唯一冲突打开数据库 breaker。
retry budget
如果原始请求率为 ,平均重试 次:
故障时 r 往往上升,正好放大最脆弱的下游。为服务定义:
load shedding
在数据库彻底饱和前:
- 拒绝可选报表/推荐;
- 降低 background worker;
- 使用缓存/较旧副本;
- 限制 expensive endpoint;
- 保留写入/控制面;
- 必要时进入只读或功能降级。
load shedding 是业务决策,不应完全交给随机 connection timeout。
22.5.3 为 ch34 的止血动作预留控制点
第 34 章会处理连接风暴、CPU、内存、磁盘和 I/O 过载。本章要提前提供可用 控制点,否则事故中只能粗暴重启。
控制点一:客户端并发
优点:最接近业务价值,能在请求进入数据库前止血。
控制点二:应用 pool
动态缩 pool 可能只影响新借用,不能立即终止 in-flight transaction。变更行为 按具体 driver 验证。
控制点三:PgBouncer
管理 console 可观察/控制:
这些动作风险不同:
PAUSE等待 server connection 释放,可用于维护;RECONNECT database刷新 server connection;KILL更具破坏性;- runtime
SET会形成声明漂移; - global action blast radius 可能跨服务。
必须有 exact database/instance/role guard 和复位证据。
控制点四:HAProxy
把流量移到副本/其他主库前,先确认目标容量与一致性。转移过载往往只是移动 事故。
控制点五:PostgreSQL role/database
其中 revoke/terminate 可能影响业务或锁,属于受控事故动作。不要把示例 SQL 做成无 guard 的一键脚本。
控制点六:保留管理路径
过载时最怕 DBA 也连不进去。预留:
- superuser/reserved connection;
- 独立 admin role;
- direct endpoint;
- source network allowlist;
- 小而独立的 admin pool;
- break-glass credential;
- out-of-band host access。
监控 exporter 也不应完全依赖已满的普通业务池。
每个控制点都要有回滚
事故动作表:
| 动作 | 目的 | 成功证据 | 副作用 | 复位 |
|---|---|---|---|---|
| 降 worker | 减少 arrival | queue/DB active 降 | backlog 增 | 分阶段恢复 |
| 缩 app pool | 限制 client | acquire wait 可控 | request reject | 恢复声明 |
| pool PAUSE | 维护/切换 | server released | client wait | RESUME |
| RECONNECT db | 刷新 backend | role/path probe 通过 | login burst | 无持久配置 |
| HAProxy drain | 摘除 backend | sessions 收敛 | 容量下降 | enable/weight |
| cancel query | 释放资源 | query 消失 | 事务 abort | 应用重试 |
| terminate | 强制止血 | backend 结束 | outcome unknown | reconcile |
“止血成功”不等于“事故解决”。必须保留证据、找根因和复位。
最小过载仪表盘
应用:
PgBouncer:
PostgreSQL:
代理:
端到端 correlation 必须有 service、database、user、application_name 和时间。
本节检查表
参考资料
- PostgreSQL 18:Client Connection Defaults
- PostgreSQL 18:Server Configuration
- PgBouncer:Configuration
- PgBouncer:Administration console
上一节:路由与故障切换 · 返回本章目录 · 下一节:Pigsty 服务接入层 · 查看全书目录 · 查看索引中心