22.6 Pigsty 服务接入层
Pigsty 不发明 PostgreSQL 的主库、副本或 session 语义。它把:
inventory intent
-> Patroni role API
-> HAProxy service
-> PgBouncer/PostgreSQL destination
-> DNS/VIP/client service material
-> metrics and administration组合成可交付实现。
理解 Pigsty 服务层的关键不是记命令,而是能把任何观察反向映射到原生组件。
22.6.1 服务定义、角色选择与端口
默认变量
本章参考实现的关键声明形态:
pgbouncer_enabled: true
pgbouncer_port: 6432
pgbouncer_poolmode: transaction
pgbouncer_sslmode: disable
pg_service_provider: ''
pg_default_service_dest: pgbouncer
pg_default_services:
- { name: primary, port: 5433, dest: default,
check: /primary, selector: "[]" }
- { name: replica, port: 5434, dest: default,
check: /read-only, selector: "[]",
backup: "[? pg_role == `primary` || pg_role == `offline` ]" }
- { name: default, port: 5436, dest: postgres,
check: /primary, selector: "[]" }
- { name: offline, port: 5438, dest: postgres,
check: /replica,
selector: "[? pg_role == `offline` || pg_offline_query ]",
backup: "[? pg_role == `replica` && !pg_offline_query]" }版本和自定义配置可能不同。读取实际 inventory、role defaults 与 rendered file,不要把这段当成跨版本常量。
dest
服务 destination 可以表达:
default 使用 pg_default_service_dest
postgres PostgreSQL pg_port,常见 5432
pgbouncer PgBouncer pgbouncer_port,常见 6432
number 指定端口因此:
primary/replica dest=default在本章 pg_default_service_dest=pgbouncer 时走连接池;如果用户改成
postgres,同一个 5433/5434 就绕过池。
端口名不能替实际路径。
check
check 是 Patroni REST health path:
/primary
/replica
/read-onlyHAProxy 对成员的 8008 检查,数据流则去 dest。角色判断来自 Patroni,
不是 HAProxy 解析 PostgreSQL protocol。
selector
selector 从 cluster member inventory 中选普通 backend。
selector: "[]"表示全集。
offline 示例只选择:
pg_role == offline OR pg_offline_query这让平台能把特定 replica 标为重查询目标。selector 是期望集合,运行时健康 检查仍可能摘除不合格成员。
backup
backup selector 形成 HAProxy backup server。它决定正常集合不可用时是否 降级。
要把 backup 语义写进服务合同:
- replica 回 primary 是否允许;
- offline 回普通 replica 是否允许;
- backup 激活是否告警;
- 目标是否有容量;
- client
target_session_attrs会接受还是拒绝。
pg_service_provider
默认空值通常在每个 PostgreSQL node 上交付 local HAProxy service。
也可指定专用 HAProxy node group。此时要重新设计:
- provider 高可用;
- provider 到数据库网络;
- DNS/VIP/multi-host;
- config rollout;
- source IP/HBA;
- stats/metrics;
- 故障域。
把 HAProxy 从数据库节点移出,不自动获得入口 HA。
VIP 与 DNS
相关声明包括:
pg_vip_enabled: false
pg_vip_address: 127.0.0.1/24
pg_vip_interface: auto
pg_dns_suffix: ''
pg_dns_target: auto这是交付入口的机制选择。启用前要按第 22.1.3 节验证网络、仲裁、DNS cache 与证书,不能因为变量存在就宣称通过。
自定义业务服务
可以在 pg_services 添加服务,而不是修改默认列表。例如概念上:
pg_services:
- name: shop-ro
port: 5444
dest: pgbouncer
check: /read-only
selector: "[? pg_role == `replica` && !pg_offline_query]"生产声明还应补:
- backup/fail-closed;
- maxconn;
- balance;
- options/rise/fall;
- owner 和用途;
- TLS/网络;
- driver endpoint。
不要为每个应用随意开端口;只有语义或资源/失败域不同才需要新服务。
22.6.2 PgBouncer、HAProxy 与数据库的证据链
第一步:声明证据
从 reviewed inventory 提取 secret-free projection:
cluster/member addresses
pg_role/pg_offline_query
pg_services/default services
default destination
PgBouncer mode/port/budget
VIP/DNS/provider
declared users and pgbouncer participation凭据值不进入报告,只记录:
present
source class
rotation owner第二步:rendered HAProxy
本章 /etc/haproxy/pg-test-*.cfg 投影:
primary :5433 -> all members :6432, /primary
replica :5434 -> members :6432, /read-only, primary backup
default :5436 -> all members :5432, /primary
offline :5438 -> pg-test-3 :5432, pg-test-2 backup, /replica同时核对:
bind/mode/maxconn
balance
health method/path/status
inter/fastinter/downinter
rise/fall
shutdown-sessions
slowstart
backend maxconn/maxqueue
member address/destination/check port/backup只核对文件 diff 仍不够;进程可能未 reload 或 runtime state 不同。
第三步:HAProxy runtime
从 stats socket/API 看:
frontend OPEN
backend UP/DOWN
health code
last state change
sessions/queue
backup activation敏感 stats user/password 不输出。使用 local protected socket 比把管理页面凭据 写入脚本更安全。
第四步:PgBouncer config
在 local Unix admin socket:
SHOW CONFIG;
SHOW DATABASES;
SHOW USERS;
SHOW POOLS;
SHOW STATS;本章 safe projection:
pool_mode=transaction
listen_addr=0.0.0.0
listen_port=6432
max_client_conn=20000
default_pool_size=50
reserve_pool_size=30
reserve_pool_timeout=1
query_wait_timeout=120
max_db_connections=100
max_user_connections=100
max_prepared_statements=256
server_reset_query=DISCARD ALL
server_reset_query_always=0
client_tls_sslmode=disable
unix_socket_dir=/run/postgresql不要采集:
- password;
- SCRAM verifier;
- auth file 内容;
- inventory secret;
- admin credential。
数据库 LOGIN 不等于池化身份已交付
本章开发过程中故意撞到一个重要边界:
CREATE ROLE pg36_ch22_app LOGIN PASSWORD ...
direct PostgreSQL auth works
PgBouncer auth fails因为本章 Pigsty 默认:
pgbouncer_auth_query: falsePgBouncer authentication surface 由声明式用户清单管理。只有数据库 catalog 里存在 role,不等于 pooler 的 auth file/query 已经认识它。
生产用户应在 Pigsty pg_users 中声明并明确:
- name: pg36_shop_app
password: <secret reference/material>
pgbouncer: true实际字段与 secret workflow 以当前版本文档和组织规范为准。不要手改
userlist.txt 制造不可追踪漂移。
本章 formal run 因此使用既有、Pigsty 已声明的 nonproduction test 用户,
只创建专属 schema/table;脚本永不修改或删除该 role。
若启用 pgbouncer_auth_query,还要评审:
auth_user与查询权限;- query 在 replica/primary 的行为;
- password rotation;
- role expiration;
- auth database;
- failover;
- secret exposure。
第五步:PostgreSQL 原生状态
对每个 member:
SELECT pg_is_in_recovery(),
current_setting('transaction_read_only'),
current_setting('cluster_name'),
current_setting('port'),
pg_postmaster_start_time();并观察连接预算:
SELECT name, setting, unit, source
FROM pg_settings
WHERE name IN (
'max_connections',
'superuser_reserved_connections',
'reserved_connections',
'idle_in_transaction_session_timeout',
'statement_timeout',
'max_locks_per_transaction',
'work_mem',
'temp_buffers'
);pg_postmaster_start_time() 在本章用来把经过 local Unix socket 的 PgBouncer
session 映射回具体 member;inet_server_addr() 对 Unix backend 可能为空。
第六步:从 client 走完整路径
每个 service 用真实 database/user:
SELECT pg_is_in_recovery(),
current_setting('transaction_read_only')::boolean,
current_setting('cluster_name'),
current_setting('port')::integer,
pg_backend_pid(),
pg_postmaster_start_time();预期:
| service | recovery | read_only | path |
|---|---|---|---|
| primary 5433 | false | false | HAProxy → PgBouncer |
| replica 5434 | true | true | HAProxy → PgBouncer |
| default 5436 | false | false | HAProxy → PostgreSQL |
| offline 5438 | true | true | HAProxy → PostgreSQL |
再到每台 PgBouncer SHOW POOLS,证明 pooled endpoint 真正在对应 process
形成了 database/user pool。
第七步:行为证据
配置与角色通过后仍要测:
- 12-client/2-server queue;
- backend reassignment;
- session state 丢失/泄漏;
- protocol prepared;
- SQL PREPARE negative;
- async token visibility;
- planned switch/reconnect;
- final config/topology restore。
这才完成从声明到用户体验的链。
证据矩阵
| Claim | 声明 | 渲染 | runtime | SQL/client |
|---|---|---|---|---|
| 5433 主写 | service check/dest | primary cfg | backend status | writable |
| 5434 副本优先 | backup/selector | replica cfg | selected pool | read-only/member |
| 事务池 | pool mode | pgbouncer ini | SHOW CONFIG/POOLS | PID reassignment |
| 2 server cap | runtime override | N/A | sv_active ≤ 2 | 12 clients complete |
| prepared 支持 | max_prepared | SHOW CONFIG | two server PID | correct protocol results |
| switch recovery | Patroni/service | health config | topology/pool refresh | token reconcile |
22.6.3 配置变更、reload 与连接行为验证
不要直接编辑 rendered file
错误流程:
vim /etc/haproxy/pg-test-primary.cfg
systemctl reload haproxy问题:
- inventory 不知道;
- 下次 automation 覆盖;
- 多节点不一致;
- review/rollback 不完整;
- secret/权限可能漂移。
正确流程:
edit reviewed Pigsty declaration
-> render diff/plan
-> validate generated config
-> staged reload
-> runtime observation
-> client behavior test
-> commit evidence/rollbackservice tag
参考代码中服务生成/reload 由 pg_service 相关 task/tag 管理,典型调用形态:
./pgsql.yml -l pg-test -t pg_service生产执行前必须按当前 Pigsty 版本查看 help/plan、限定 inventory 和 host。 不要从书中复制命令直接指向未知集群。
render task 会生成 service config,并在 reload 前运行 HAProxy config check。
配置校验
原生检查:
haproxy -f /etc/haproxy/haproxy.cfg -c -q它证明语法/引用可加载,不证明路由语义正确。
PgBouncer reload:
RELOAD;
SHOW CONFIG;不是所有配置都支持在线改变;某些需要 reconnect/restart。SHOW CONFIG 的
changeable 列与当前文档共同决定。
reload 与现有连接
必须回答:
old HAProxy process 是否 drain
existing TCP 是否保留
new connections 是否使用新 config
PgBouncer existing client/server pool 是否继承
authentication file rotation 对既有 session 是否影响
pool size 改变对已有 server connection 如何收敛“reload 成功”不能替代这些答案。
role change 与 config change 是两类变更
config change:
declaration -> render -> reloadrole change:
Patroni/DCS -> health convergence -> pool/client refresh二者可能同时发生,但 rollback 不同。故障切换时不应顺手修改持久配置, 否则难以分辨恢复来自哪项动作。
本章 runtime pool override 只用于实验,并在切换前恢复,正是为了隔离变量。
staged rollout
多入口环境:
- 选一个无生产或低流量 provider;
- render/check;
- reload;
- direct health + client probe;
- 观察 queue/error/session;
- 扩到下一 provider;
- 完整端点矩阵;
- 保留旧配置与回滚。
若所有 provider 同时 reload,错误配置会同时摧毁入口冗余。
变更后的强制验证
declaration projection equals reviewed intent
rendered files equal expected member/dest/check/backup
all proxy instances loaded intended config
runtime backend states make sense
PgBouncer config/pools within budget
primary endpoint writable
replica/offline endpoint readonly + allowed member
direct endpoint bypasses pool
session/prepared compatibility suite passes
old/new connection behavior matches change plan如果变更涉及 role/promotion,再执行 pool role-state refresh 检查。
回滚
回滚不是把文件复制回去:
restore declaration
render/check
staged reload
verify runtime
verify client path
close/refresh incompatible existing sessions if needed
record final state如果数据库 role 已在期间改变,旧 rendered config 的成员角色仍由 health check 动态判断,但 selector/backup/destination 可能不再合适,要重新评审。
secret 与证据
服务变更会接触:
- inventory password;
- PgBouncer userlist/verifier;
- HAProxy stats auth;
- TLS key;
- HBA/identity。
证据只保留:
hash/projection/presence
mode/owner
rotation metadata
behavioral result不要把整个 inventory、auth file 或 config 原文无差别上传。正式 lab 对
临时 credential inventory 要求 mode 0600,使用后删除副本,报告
secret_values_exported=0。
本节检查表
[ ] 实际版本的 pg_default_services 已读取
[ ] dest/check/selector/backup 分别解释
[ ] local/dedicated service provider 的失败域明确
[ ] PostgreSQL LOGIN 与 PgBouncer auth delivery 分开验收
[ ] rendered HAProxy 与 runtime stats 都检查
[ ] SHOW CONFIG/POOLS 不导出敏感材料
[ ] client probe 映射到具体 member/role
[ ] 变更来自 inventory,不手改渲染产物
[ ] config check 只是语法门,不是完成条件
[ ] staged reload 验证 old/new connection
[ ] role change 后重新验证 pool state
[ ] rollback 恢复声明、runtime 与 client behavior参考资料
- Pigsty:PostgreSQL Service
- Pigsty:PgBouncer Administration
- PgBouncer:Configuration
- HAProxy:Configuration tutorials
上一节:连接预算与过载边界 · 返回本章目录 · 下一节:实战:写入、只读与管理三类接入 · 查看全书目录 · 查看索引中心