24.4 观察与告警契约
监控系统不会自动知道“什么对用户重要”。它只会忠实地计算你交给它的数值。
wrong semantic + perfect query
= precisely wrong alert因此告警规则之前要有 observation contract:
objective
-> source
-> metric/event type
-> good/total selector
-> dimensions
-> query
-> missing semantics
-> fallback
-> owner/action本节产出第 25 章的实现合同,而不提前声称指标和 page 已经部署。
24.4.1 每个 SLI 的数据源、查询、维度和缺失语义
一个 SLI 需要哪些字段
最小 observation contract:
| 字段 | 问题 |
|---|---|
objective_id | 它实现哪个 SLO/control? |
source | 谁产生原始事实? |
metric_type | counter、histogram、gauge 还是 event? |
good_selector | 哪些事件进入分子? |
total_selector | 哪些事件进入分母? |
dimensions | 按哪些有界维度分解? |
query_template | 如何从窗口计算? |
missing_semantics | series 消失代表什么? |
fallback | 主 observation path 失败后看什么? |
metric_status | 已存在、待实现还是 deprecated? |
少一个字段就可能改变结论。
本章的五个来源
| objective | source | type | 状态 |
|---|---|---|---|
| availability | pg36_shop_request_outcomes_total | counter | 应用待实现 |
| latency | pg36_shop_request_duration_seconds | histogram | 应用待实现 |
| freshness | pg36_shop_commit_visibility_probes_total | counter | synthetic probe 待实现 |
| correctness | pg36_shop_reconciliation_mismatches | gauge | 核对任务待实现 |
| restore readiness | pg36_shop_restore_evidence_age_seconds | gauge | 证据导出器待实现 |
这些是本书定义的应用 metric contract,不是 Pigsty 内置指标。metric_status
故意保留“to implement”,防止目录文档冒充运行事实。
availability query
原始 counter:
pg36_shop_request_outcomes_total{
service="pg36_shop",
operation_class="place-order",
environment="production",
eligible="true",
outcome="good|bad|unknown"
}bad ratio 模板:
1 -
sum(
rate(pg36_shop_request_outcomes_total{
service="pg36_shop",
operation_class="place-order",
eligible="true",
outcome="good"
}[$window])
)
/
clamp_min(
sum(
rate(pg36_shop_request_outcomes_total{
service="pg36_shop",
operation_class="place-order",
eligible="true"
}[$window])
),
1
)unknown 在核对前不进入 good,所以会消耗预算。后续事件若核对为 committed
once,可通过事件管道作有审计的最终分类;不能在 dashboard 手工改值。
clamp_min 只防除零,不解决 telemetry missing。no traffic、counter absent 和
ingestion broken 要由独立 freshness/metamonitoring 判断。
latency query
histogram 需要 le="0.25" bucket:
1 -
sum(
rate(pg36_shop_request_duration_seconds_bucket{
service="pg36_shop",
operation_class="place-order",
eligible="true",
availability_good="true",
le="0.25"
}[$window])
)
/
clamp_min(
sum(
rate(pg36_shop_request_duration_seconds_count{
service="pg36_shop",
operation_class="place-order",
eligible="true"
}[$window])
),
1
)这里示意把快速失败留在 denominator 而不进入 good bucket。实际 instrumentation 也可以统一用 outcome counter 与 duration histogram 通过 recording rule 对齐, 但必须有自动测试证明:
eligible count in availability
== eligible count in latency否则两个 SLO 使用不同分母,会产生无法解释的预算。
freshness query
每个 probe:
write token
commit reconciled
poll declared read path
within_bound = true/false
read_path = replica|primary|applicationbad ratio:
1 -
sum(
rate(pg36_shop_commit_visibility_probes_total{
service="pg36_shop",
eligible="true",
within_bound="true"
}[$window])
)
/
clamp_min(
sum(
rate(pg36_shop_commit_visibility_probes_total{
service="pg36_shop",
eligible="true"
}[$window])
),
1
)probe absence:
unknown + probe-pipeline failure不能用 pg_last_xact_replay_timestamp() 填补,因为它没有对应当前 commit。
correctness query
max(
pg36_shop_reconciliation_mismatches{
service="pg36_shop"
}
)需要配套:
last_success_timestamp;- reconciliation input boundary;
- rule/query version;
- invariant;
- result hash。
只导出 0 而不监控 job freshness,会在核对任务停摆后永远显示“零差异”。
missing semantics:
stale or absent reconciliation = control failurerestore evidence age
max(
pg36_shop_restore_evidence_age_seconds{
service="pg36_shop",
recovery_class="named-pitr"
}
)阈值 90 天:
<= 7,776,000 seconds control current
> 7,776,000 seconds evidence stale
absent failed control, not infinite freshness导出器必须只接受验证通过且完整性 hash 正确的 restore manifest。不能因为目录中 有一个新文件,就把 evidence age 归零。
PostgreSQL statistics 用于解释原因
PostgreSQL 18 提供:
pg_stat_activity:backend、状态、query/transaction 时间;pg_stat_database:transaction、block、tuple 与 session 统计;pg_stat_replication:sender、state、LSN 与同步状态;pg_stat_wal_receiver:standby receiver;pg_stat_archiver:归档成功/失败;pg_stat_io:按 backend/object/context 的 I/O;pg_stat_ssl:连接 TLS;- lock 与 progress views。
完整目录见 PostgreSQL Monitoring Database Activity。
这些视图回答:
what PostgreSQL is doing不直接回答:
whether pg36_shop users completed place-order correctly访问统计应使用 pg_monitor 等受控预定义角色或更窄授权,而不是让 exporter
成为 superuser。预定义角色边界见
Predefined Roles。
Pigsty v4.4 的实现层
当前 Pigsty 监控栈:
| 组件 | 职责 |
|---|---|
| VictoriaMetrics | 时序 ingestion、storage、query |
| VictoriaLogs | 结构化日志 |
| VMAlert | 规则评估 |
| Alertmanager | 聚合、抑制、路由、通知 |
| Grafana | dashboard 与调查入口 |
| exporter/agent | 暴露数据库、主机和组件事实 |
Pigsty v4 已从旧的 Prometheus/Loki 存储迁到 VictoriaMetrics/VictoriaLogs; VMAlert 仍使用 PromQL-compatible 规则。不要复制旧文档后声称 v4 仍以 Prometheus server 存储时序。当前架构见 Monitoring System。
PostgreSQL、PgBouncer、host、load balancer 尽量通过:
cls cluster identity
ins instance identity
ip address identity关联,详见 PGSQL Monitoring。
维度:服务与组件分别建模
应用 SLI:
service
operation_class
environment
region/cell
outcome class
synthetic组件 telemetry:
cls
ins
ip
database
user/role (bounded and privacy reviewed)连接方式:
service catalog:
pg36_shop -> pg-test
metric correlation:
service="pg36_shop"
dependency_cls="pg-test"不要强行把 service 填成 ins,也不要把所有 database metric 复制一份
customer label。
cardinality 是可靠性和隐私问题
禁止 label:
customer_id;tenant_id;order_id;- raw SQL;
- error message;
- stack trace。
原因:
- series 数无界增长;
- query 和 rule 变慢;
- monitoring storage 自身失稳;
- 用户数据进入广泛可见系统;
- label 变化让 aggregation 不可靠。
使用:
- bounded error class;
- normalized SQL fingerprint;
- exemplar/correlation token;
- 受控日志查明具体事件。
missing-data truth table
| traffic/probe | SLI series | 结论 |
|---|---|---|
| 有预期流量 | 存在 | 计算 SLI |
| 有预期流量 | 缺失 | observation failure |
| 无真实流量 | synthetic 存在 | limited synthetic evidence |
| 无真实流量 | synthetic 缺失 | unknown |
| exporter 存在 | app SLI 缺失 | component observable, service unknown |
| app SLI 存在 | Alertmanager canary 失败 | health known, notification path broken |
“没有错误 series”与“error counter value is zero”不是一回事。
24.4.2 告警必须绑定用户影响、首个安全动作和所有者
page 的门槛
Prometheus 官方 alerting practices 总结为:
- 保持简单;
- 对症状告警;
- 用良好 console 定位原因;
- 避免无事可做的 page。
本章把 page 定义为:
urgent
important
actionable
real
owned缺一项就应考虑 dashboard、ticket 或删除。
一个 alert contract
每个 accepted alert 至少包含:
id
class
objective
expression
long/short window
severity and route
for
user impact
owner
route id
runbook
first safe action
verification
dashboard
missing semantics
silence policy
test
review expiry这比:
alert: DatabaseHighCPU
expr: cpu > 80
severity: critical多出来的内容,正是值班可行动性的来源。
user impact 要具体
差:
database is unhealthy好:
eligible order attempts are failing or unreconciled fast enough
to spend 2% of the 28-day availability budget in one hour差:
replica lag high好:
commit-correlated reads on the declared replica path miss
the five-second visibility boundfirst safe action 不是最终修复
fast-burn availability page:
first safe action:
freeze latest risky release
reconcile unknown order outcomes before retrying writes它没有假设根因。之后 Runbook 才检查应用、入口、pool、PostgreSQL、锁和拓扑。
correctness page:
freeze affected writes
preserve reconciliation boundary before repair不能先运行“修复 SQL”,否则会覆盖事故证据。
metamonitoring page:
establish an independent blackbox view
before changing the monitored database监控断了时先恢复观察,不要凭空重启数据库。
owner 必须有 route
owner_function=service 仍不够。规则要带:
route_id
schedule
escalation
notification grouping
repeat intervalroute 要用 canary 验证:
synthetic alert
-> rule evaluator
-> Alertmanager
-> receiver
-> acknowledgement record不能只看 Alertmanager 进程 up。
for 防短暂抖动,但会增加检测延迟
Prometheus/VMAlert 风格规则可以使用:
for: 2m条件必须持续 2 分钟才 firing。它适合滤除短 blip,但不是越大越好:
evaluation interval
+ query window behavior
+ for
+ notification delay
+ human acknowledgement
= practical detection timecorrectness mismatch 可以 for: 0m,因为单个已确认 mismatch 的后果不同。
当前 Prometheus 规则语义还支持 keep_firing_for,用于条件短暂消失后继续
firing 一段时间;使用前要确认 VMAlert 当前版本的兼容和行为,并通过 rule
test 验证。官方字段见
Alerting rules。
silence 不是关闭问题
silence 必须有:
- incident/change id;
- owner;
- reason;
- exact matcher;
- start/end;
- replacement observation;
- review。
禁止:
silence service=* severity=critical for 30 days计划维护也应尽量使用 route/inhibition 和用户 SLO 的明确政策,而不是让所有 信号消失。
verification 决定何时恢复
fast-burn 恢复:
long and short windows recover
AND sampled idempotency tokens reconcile
AND no correctness control fails只看到 alert resolved 可能是:
- series 消失;
- label 改变;
- rule reload 失败;
- traffic 归零;
- silence;
- query error。
Runbook 必须检查 missing semantics 和用户结果。
alert 要有生命周期
规则不是写完永存:
owner
created
last tested
last fired
false-positive review
runbook validity
expiry/review date
replacement/deprecationorphaned route 或过期 runbook 应使 CI/治理 review 失败。
24.4.3 症状告警、原因告警与容量预测分开
症状 page
症状直接表示用户或数据后果:
- availability fast burn;
- latency fast burn;
- commit-correlated freshness violation;
- correctness mismatch;
- imminent durability loss;
- observation path loss 导致服务状态不可知。
它回答:
why wake a human now?原因 telemetry
原因帮助定位:
- CPU;
- disk latency;
- lock waits;
- pool queue;
- replica WAL distance;
- cache hit ratio;
- autovacuum backlog;
- connection count;
- Patroni member state。
同一用户症状可能有多个原因;同一原因也可能被 redundancy 吸收而没有用户 影响。若每个原因都 page:
one incident
-> CPU page
-> lock page
-> pool page
-> latency page
-> replica page值班收到五个 notification,却没有更多信息。
原因应进入:
- linked dashboard;
- diagnostic annotation;
- bounded ticket;
- automatic enrichment。
两个允许越过“用户症状”的例外
完整性/保密性
一条跨租户数据或 confirmed corruption 即使用户尚未报告,也需要立即处理。
迫近耐久性
例如所有可恢复副本/备份路径都失效且继续运行会导致不可恢复数据风险。此时 page 的依据是已定义的 durability control,不是随意的 component threshold。
例外仍要 owner、Runbook、action 和 verification。
容量是有期限的 ticket
容量预测:
forecast_days_to_capacity < lead_time + safety_margin通常不是当前 user incident,因此:
- 创建 owned ticket;
- 带 forecast confidence;
- 检查 demand/query mix/retention;
- 给 due date;
- 不在凌晨 page。
若容量已经造成 latency/availability,则症状 SLO 会 page;capacity facts 作为 诊断。
本章候选:
PG36ShopCapacityHorizon
route ticket
forecast horizon 14 days
first action validate demand/headroom/retention/query mixmetamonitoring
监控系统也会失败:
- exporter 停止;
- agent 无法发送;
- VictoriaMetrics ingestion/query 失败;
- VMAlert rule evaluation error;
- Alertmanager route 失败;
- receiver 不可达;
- dashboard query 误导。
有效 metamonitoring:
whitebox
ingestion errors / rule errors / queue
blackbox
expected series freshness
external service probe
notification canary end-to-endPrometheus alerting practices 也建议用贯穿 PushGateway/Prometheus/ Alertmanager/email 的 blackbox 测试,而不是只盯每个组件进程。Pigsty v4 中要 把这个思想映射到 VictoriaMetrics/VMAlert/Alertmanager。
分类矩阵
| signal | class | route | 例子 |
|---|---|---|---|
| user event bad ratio | symptom | page/ticket by burn | availability |
| data invariant mismatch | integrity | page | duplicate/cross-tenant |
| WAL distance | cause | dashboard | replication diagnosis |
| pool queue | cause | dashboard | latency diagnosis |
| CPU | cause | dashboard/ticket | capacity/diagnosis |
| days-to-full | capacity | ticket | disk/storage |
| notification canary overdue | metamonitoring | page | blind operation |
本章明确拒绝的 page
候选:
PostgresInstanceDownWithoutAction被拒绝,因为:
- 一台 instance 可因 offline maintenance 合理下线;
- redundancy 可能仍满足服务;
- 没有声明用户影响;
- 没有 owner;
- 没有 Runbook;
- 没有第一安全动作。
替代:
retain instance state on topology dashboard
correlate endpoint/user-event symptoms
escalate through redundancy/durability policy if neededvalidator 会故意把它的 decision 改成 accepted,并确认合同拒绝。
24.4.4 产出供 ch25 实现的告警规则清单
七个 accepted candidates
1. PG36ShopAvailabilityFastBurn
class symptom
route page / SEV-1
windows 1h + 5m
burn 14.4x
for 2m
action freeze latest risky release;
reconcile unknown writes before retry对 99.9%:
$$ 14.4 \times (1-0.999)=0.0144 $$
即两个窗口 bad ratio 都高于 1.44%。
2. PG36ShopAvailabilitySlowBurn
route page / SEV-2
windows 6h + 30m
burn 6x
for 5m
action stop concurrent risky changes;
segment by operation and release阈值 0.6% bad ratio。
3. PG36ShopAvailabilityBudgetTicket
route ticket
windows 3d + 6h
burn 1x
for 15m
action open owned budget review用于慢性消耗,不打扰夜间值班。
4. PG36ShopCorrectnessMismatch
class integrity
route page / SEV-1
condition mismatch > 0
for 0m after confirmed reconciliation
action freeze affected writes;
preserve boundary不使用 burn rate。
5. PG36ShopFreshnessFastBurn
class symptom
route page / SEV-2
windows 1h + 5m
burn 14.4x against 99% freshness target
action route affected read-after-write journey to primary
while preserving probe tokens不要把所有 read traffic 永久移到 primary;这是有界安全动作,恢复后再评审 read policy。
6. PG36ShopCapacityHorizon
class capacity
route ticket
condition reviewed forecast < 14 days
action validate demand/headroom/retention/query mix预测没有足够历史时,创建 evidence-quality ticket,而不是编造 forecast。
7. PG36MonitoringPathBroken
class metamonitoring
route page / SEV-2
condition expected probe missing
OR rule evaluation failure
OR notification canary overdue
action establish independent blackbox view firstrule skeleton
第 25 章可从下面开始,但必须使用 recording rules 和测试后的真实 label:
groups:
- name: pg36-shop-slo
rules:
- alert: PG36ShopAvailabilityFastBurn
expr: |
(
pg36_shop:sli_availability_bad_ratio:rate1h
> 14.4 * (1 - 0.999)
)
and
(
pg36_shop:sli_availability_bad_ratio:rate5m
> 14.4 * (1 - 0.999)
)
for: 2m
labels:
severity: sev1
service: pg36_shop
class: symptom
annotations:
summary: "pg36_shop availability burns fast"
runbook: "runbook://RB-USER-SYMPTOM"
dashboard: "dashboard://pg36-shop-slo"这段只是规则语义骨架,不能直接部署,因为:
- recording rules 尚未实现;
- production environment/region labels 尚未固定;
- route 与 receiver 仍是教学标识;
- real owner 尚未批准;
- rule evaluation interval 尚未纳入检测时间;
- test fixture 尚未建立。
第 25 章必须交付什么
Instrumentation
- counters/histograms 的真实采集;
- eligible/good classifier tests;
- commit token probe;
- reconciliation freshness;
- restore evidence exporter;
- bounded labels。
Recording rules
- 5m、30m、1h、6h、3d 等窗口;
- label-preserving aggregation;
- reset 和 counter semantics;
- no-traffic/missing 分支;
- rule unit tests。
Alert rules
- 七个 accepted candidates;
- actionless candidate 保持 rejected;
for和 evaluation delay;- route/inhibition/silence;
- review expiry。
Dashboards
- SLI、target、budget remaining;
- numerator/denominator;
- eligible classification;
- recent changes;
- component cause drill-down;
- missing telemetry state。
Delivery tests
- synthetic rule firing;
- label/annotation assertions;
- Alertmanager grouping;
- notification canary;
- acknowledgement;
- resolved 与 missing 的区分。
交接门槛
在实现规则前逐项确认:
- objective id 与 SLO policy 一致;
- metric status 从“待实现”变更有 evidence;
- good/total selector 经过代码测试;
- histogram 有目标 bucket;
- unknown outcome 不会被算 good;
- missing series 有独立规则;
- labels 有界且不泄露数据;
- Pigsty identity 使用
cls/ins/ip; - component facts 不冒充 user SLI;
- multiwindow 使用 AND;
- page 有 owner、route、Runbook、action 和 verification;
- capacity 进入 ticket;
- cause 进入 dashboard;
- correctness/durability 例外有独立 control;
- notification path 自身被测试;
- real pager 测试获得明确授权;
- sandbox 规则没有被称为 production-approved。
完整输入见:
下一节处理这些指标、变更和操作留下的证据:证据必须足够证明决定,却不能把 秘密和个人数据无边界地复制到治理系统。
上一节:SOP、Runbook 与变更治理 · 返回本章目录 · 下一节:证据、审计与合规 · 查看全书目录 · 查看索引中心