11.6 发布窗口中的平台观察
数据库 catalog 只能回答“当前对象是什么、谁在等谁”;发布平台还要回答“哪条流量进入哪里、影响面多大、过去几分钟发生了什么、是否仍在安全水位内”。
一次发布观察闭环:
change identity + UTC window
→ exact Pigsty service / database / role / application_name
→ PostgreSQL live catalog
→ Prometheus/Grafana historical trend
→ application release + SLI/error evidence
→ pause/switch/contract decision仪表盘不是 DDL 正确性的替代品;SQL postcheck 也不是容量与用户影响的替代品。
11.6.1 从服务入口隔离实验流量
Pigsty 的四类默认服务
Pigsty v4.4 的默认 PostgreSQL 服务:
| Service | Port | 默认路径 | 典型用途 |
|---|---|---|---|
| primary | 5433 | HAProxy → primary pool | 生产读写 |
| replica | 5434 | HAProxy → replica pool | 生产只读 |
| default | 5436 | HAProxy → primary PostgreSQL | DBA、ETL、直接写 |
| offline | 5438 | HAProxy → offline/replica PostgreSQL | OLAP、离线、交互 |
端口与 selector 来自 pg_default_services / pg_services 配置,以目标集群的当前 Pigsty Service 文档 和 inventory 为准。
模式变更不应随便借用 production application pool:
- session-level DDL 设置可能被 pool 复用污染;
- transaction pooling 可能不支持所需 session 语义;
- maintenance traffic 与用户请求难以区分;
- pool timeout 与 migration timeout 可能互相覆盖;
- 连接数/排队会混入应用 SLI。
通常使用受控 DBA/default direct service 或专用 migration service;仍必须确认它路由到 writable primary。
“连到 5436”仍不是目标证明
连接后第一条证据:
SELECT
current_database(),
session_user,
current_user,
current_setting('server_version'),
pg_is_in_recovery(),
current_schemas(false),
current_setting('application_name');还要验证:
- cluster/instance identity;
- expected schema version;
- object owner/marker;
- target relation OID/definition;
- transaction pooling 是否绕过;
- connection string 没有展开 secret;
- role 能力只覆盖本次 change。
错误 primary 上的正确 DDL 仍是事故;正确 primary 上的错误 database 也是。
本章 service file 只保存受控连接 identity,脚本使用:
service=pg36-admin
application_name=pg36-ch11-<phase>manifest 记录 service name,不展开密码/URI。
用 application_name 切出发布流量
每个 phase 使用稳定前缀:
pg36-ch11-lock-holder
pg36-ch11-lock-waiter
pg36-ch11-backfill
pg36-ch11-index-build
pg36-ch11-partition-attach
pg36-ch11-partition-detach这样可以在:
SELECT
pid,
backend_start,
application_name,
state,
xact_start,
query_start,
wait_event_type,
wait_event,
left(query, 300)
FROM pg_stat_activity
WHERE application_name LIKE 'pg36-ch11-%';区分 phase,保存 live evidence,并让 reset 在 worker 存活时 fail closed。
application_name 是可伪造 label,不是 authentication/authorization。取消 session 前仍要组合:
database + pid + backend_start + role + client + application + query identity防止 PID reuse 或同名前缀误伤。
隔离流量不等于隔离资源
专用 service/role/application_name 改善 attribution 和权限边界,却仍共享:
- primary CPU/IO/buffer;
- WAL 与 replication;
- disk;
- autovacuum;
- lock manager;
- checkpoint;
- network;
- replicas 的 replay。
因此 L1 演练服务不能证明生产容量。若要在生产 shadow/backfill,必须设置实际资源和 SLI 水位。
不要为一次 DDL 临时改平台配置
例如为了让 backfill 更快,随手全局修改:
max_wal_size
checkpoint_timeout
autovacuum
statement_timeout
work_mem
max_parallel_maintenance_workers会把一个 schema change 变成 schema + config 联合 change,扩大变量和恢复面。优先使用 session/local setting;确需 config change 时,独立变更单、独立 evidence 和独立复位。
11.6.2 观察锁、复制延迟、WAL 与资源水位
从发布 SLI 开始
发布期间先看用户影响:
request success/error rate
p50/p95/p99 latency
timeout/retry rate
queue depth
connection acquisition latency
business invariant errors再解释数据库侧原因。一个 WAL spike 如果不影响 SLO 且在预算内,可能可接受;一个没有明显 CPU spike 的 lock convoy 也可能让 tail latency 立即恶化。
Pigsty dashboard 路线
Pigsty v4.4 当前文档列出的相关面板:
PGSQL Activity:
sessions, load, active/idle, locks
PGSQL Xacts:
transaction rate/time, rollback, lock
PGCAT Locks:
live activity and lock waits from catalog
PGSQL Query / PGCAT Query:
affected query family, calls, latency, plan/stat context
PGSQL Persist:
WAL, checkpoint, archive, IO, XID
PGSQL Replication:
physical/logical replication, slots, pub/sub
PGSQL Service / Proxy / Pgbouncer:
routing, backend health, queue and pool
PGSQL Instance / NODE dashboards:
CPU, memory, disk, filesystem, IO, network名称与布局会升级,以当前 Pigsty Dashboard 文档 为准,不把截图坐标或 panel ID 写进长期 runbook。
锁观察必须落回 exact graph
历史曲线回答:
when did lock waits rise?
how many sessions and how long?
which database/cluster?
did user latency rise together?live catalog 回答:
SELECT
waiter.pid AS waiter_pid,
waiter.backend_start AS waiter_epoch,
waiter.application_name AS waiter_app,
waiter.wait_event_type,
waiter.wait_event,
blocker.pid AS blocker_pid,
blocker.backend_start AS blocker_epoch,
blocker.application_name AS blocker_app,
blocker.xact_start,
blocker.state
FROM pg_stat_activity AS waiter
CROSS JOIN LATERAL unnest(
pg_blocking_pids(waiter.pid)
) AS edge(blocker_pid)
LEFT JOIN pg_stat_activity AS blocker
ON blocker.pid = edge.blocker_pid;对 DDL 还要查 relation lock:
SELECT
activity.application_name,
lock.relation::regclass,
lock.mode,
lock.granted,
lock.waitstart
FROM pg_locks AS lock
JOIN pg_stat_activity AS activity
ON activity.pid = lock.pid
WHERE lock.relation IS NOT NULL;看到 AccessExclusiveLock 不能直接杀 session;先确定 holder、waiter、队列和业务影响。
WAL 观察不是只看一个 counter
模式变更会影响:
WAL generation rate
WAL directory size
archive throughput/failure
replication slot retained WAL
replica receive/replay lag
checkpoint frequency and write pressure
network throughput
backup/PITR window单节点本章用 pg_current_wal_insert_lsn() 前后差作为相对 A/B;生产需时间序列。counter 应使用 rate/increase,并注意 restart/reset epoch。还要区分:
- generated WAL;
- sent/received WAL;
- replay progress;
- slot
restart_lsnretention; - archive queue。
主库 lag 为零不代表 replica 已应用;bytes lag 与 time lag也不能互换。
Replication lag 的停止线
backfill/validation/CREATE INDEX 可让 replica:
- replay 落后;
- read query 与 replay 冲突;
- WAL 堆积占盘;
- failover 后 RPO/RTO 风险增加。
停止条件应同时绑定:
max replay bytes/time lag
max retained WAL / minimum disk free
replica read SLI
archive success
failover readiness policy如果发布时 primary failover,默认暂停 change,重新验证:
new primary identity
committed schema phase
checkpoint state
concurrent index/partition intermediate state
worker ownership
application routing不能假设脚本连接自动漂移后可从上一行继续。
资源水位与 workload attribution
至少保存:
| 维度 | 观察 | 解释 |
|---|---|---|
| CPU | instance/node usage | transform/index build CPU |
| IO | read/write latency/throughput | scan/rewrite/checkpoint |
| disk | data/WAL/temp free | rewrite double space/retention |
| memory | buffer/cache/OS pressure | scan cache displacement |
| connection | app/admin/pool queues | migration contention |
| vacuum | dead tuples/xmin/age | backfill cleanup debt |
| query | user + migration families | regression attribution |
发布 connection 的 application_name、UTC window 和 query identity 让这些图能与具体 phase 对齐。
指标盲点也是停止条件
如果 exporter、Grafana、logs、application telemetry 任一关键链路不可用:
cannot observe ≠ no impact对于高风险 rewrite/backfill/contract,应暂停,而不是在盲区继续。监控恢复后先补采 live state,再决定 resume。
11.6.3 配置变更与模式变更分别留证
三种 identity
一次完整发布至少有:
application release:
image/git SHA, rollout/flag, version population
database migration:
migration ID, source checksum, phase, schema post-state
platform/config change:
inventory commit, rendered diff, apply task, runtime value它们相互引用,但不能共享一个模糊“release-2026-07-29”后失去可归因性。
Database evidence
本章 evidence:
manifest.txt
preflight.txt
setup/expand/validate/switch outputs
lock-attempt.stderr
lock-graph.csv
default-catalog.csv
constraint-before.csv
constraint-after.csv
backfill-interrupted.json
backfill-resumed.json
partition-summary.json
contract-gate.stderr
verify.txt
model-verify-after.txt
review.txtmanifest 保存:
- UTC capture time;
- action/service;
- psql/Python/server version;
- database/user/recovery;
- source SHA-256。
它不保存 secret,也不把 dynamic PID/filenode/timing 当 golden。
Pigsty config evidence
如果本次确实改变 pg_services、PostgreSQL 参数或监控配置,另存:
inventory/config source commit
target cluster/instance selector
rendered before/after diff
validation/lint output
exact Ansible tag/command
changed vs restarted instances
pg_settings source/sourcefile/pending_restart
service routing/health postcheck
rollback/reapply command不要只保存 SHOW parameter。runtime value 不能证明它来自哪个 inventory version,也不能说明 restart 后会不会保持。
反过来,config repo diff 也不能证明 runtime 已生效;两边都要。
Schema migration 不应修改不可变历史
baseline-v0.6-proposal.json 不改写 v0.1 baseline,而是:
base checksum
+ dependency v0.5 checksum
+ SAFE-MIGR-006 statement change
+ DEFAULT-VERS-010 runtime check change
+ ch11 evidence paths
+ promotion conditions同理,生产 migration 文件一旦发布,不应原地改内容后保留同 migration ID。若修复:
- 发布新 migration identity;
- 说明依赖和前置 phase;
- 保留旧 artifact/checksum;
- fresh install 继续由同一权威链生成或验证。
Change log 与 evidence package
建议目录:
change-id/
intent.md
approvals/
application/
database/
platform/
observations/
decision-log.md
final-review.jsondecision log 记录:
timestamp UTC
observer/decision owner
current phase
watermarks
continue/slow/pause/switch/contract
reason and evidence links
next review time这样事故复盘能回答“当时基于什么证据继续”,而不是只有最后成功/失败。
敏感信息与保留期
SQL、query parameter、client address、logs、application payload 可能包含:
- customer identifiers;
- tokens/credentials;
- financial/personal data;
- internal topology。
证据包要:
redact secrets and payload
retain stable hashes/IDs when enough
apply access control
declare retention and deletion
preserve chain of custody for incidents不要为了“完整证据”把 password-bearing URI、PGPASSWORD 或完整用户 payload 写入 artifact。
Final review 的职责边界
自动 review 可以确认:
files exist
checksums/dependencies match
SQLSTATE and catalog relationships
checkpoint monotonicity
data checksums and cleanup人/发布系统仍要确认:
production SLI acceptable
replication/disk within budget
old consumers truly zero
observation window elapsed
contract authority granted让工具拒绝它不能证明的 contract,是质量而不是自动化不完整。
本节验收问题
- 发布使用哪个 Pigsty service、port、pool/direct path;
- 连接后是否再次验证 database/role/primary/schema;
- 每个 phase 是否有独立 application_name;
- service 隔离与资源隔离是否被正确区分;
- user SLI、lock、WAL、lag、disk、pool 是否同窗观察;
- lock metric 是否能落回 exact blocker graph;
- failover 后是否默认暂停并重新发现 state;
- 监控盲点是否是明确停止条件;
- application、database、platform identity 是否分离;
- config source diff 与 runtime postcheck 是否都有;
- migration/source artifacts 是否 checksum 固定且不可变;
- evidence 是否脱敏、有权限和保留期;
- 自动 review 是否诚实拒绝无法证明的生产事实。
参考资料
- Pigsty:Service/Access
- Pigsty:PostgreSQL Dashboards
- Pigsty:PostgreSQL Metrics
- PostgreSQL 18:Monitoring Database Activity
- PostgreSQL 18:Viewing Locks
上一节:数据回填与流量切换 · 返回本章目录 · 下一节:实战:无中断演进订单模式 · 查看全书目录 · 查看索引中心