跳至内容
11.6 发布窗口中的平台观察

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 服务:

ServicePort默认路径典型用途
primary5433HAProxy → primary pool生产读写
replica5434HAProxy → replica pool生产只读
default5436HAProxy → primary PostgreSQLDBA、ETL、直接写
offline5438HAProxy → offline/replica PostgreSQLOLAP、离线、交互

端口与 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_lsn retention;
  • 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

至少保存:

维度观察解释
CPUinstance/node usagetransform/index build CPU
IOread/write latency/throughputscan/rewrite/checkpoint
diskdata/WAL/temp freerewrite double space/retention
memorybuffer/cache/OS pressurescan cache displacement
connectionapp/admin/pool queuesmigration contention
vacuumdead tuples/xmin/agebackfill cleanup debt
queryuser + migration familiesregression 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.txt

manifest 保存:

  • 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.json

decision 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,是质量而不是自动化不完整。

本节验收问题

  1. 发布使用哪个 Pigsty service、port、pool/direct path;
  2. 连接后是否再次验证 database/role/primary/schema;
  3. 每个 phase 是否有独立 application_name;
  4. service 隔离与资源隔离是否被正确区分;
  5. user SLI、lock、WAL、lag、disk、pool 是否同窗观察;
  6. lock metric 是否能落回 exact blocker graph;
  7. failover 后是否默认暂停并重新发现 state;
  8. 监控盲点是否是明确停止条件;
  9. application、database、platform identity 是否分离;
  10. config source diff 与 runtime postcheck 是否都有;
  11. migration/source artifacts 是否 checksum 固定且不可变;
  12. evidence 是否脱敏、有权限和保留期;
  13. 自动 review 是否诚实拒绝无法证明的生产事实。

参考资料


上一节:数据回填与流量切换 · 返回本章目录 · 下一节:实战:无中断演进订单模式 · 查看全书目录 · 查看索引中心

最后更新于