跳至内容

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_typecounter、histogram、gauge 还是 event?
good_selector哪些事件进入分子?
total_selector哪些事件进入分母?
dimensions按哪些有界维度分解?
query_template如何从窗口计算?
missing_semanticsseries 消失代表什么?
fallback主 observation path 失败后看什么?
metric_status已存在、待实现还是 deprecated?

少一个字段就可能改变结论。

本章的五个来源

objectivesourcetype状态
availabilitypg36_shop_request_outcomes_totalcounter应用待实现
latencypg36_shop_request_duration_secondshistogram应用待实现
freshnesspg36_shop_commit_visibility_probes_totalcountersynthetic probe 待实现
correctnesspg36_shop_reconciliation_mismatchesgauge核对任务待实现
restore readinesspg36_shop_restore_evidence_age_secondsgauge证据导出器待实现

这些是本书定义的应用 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|application

bad 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 failure

restore 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聚合、抑制、路由、通知
Grafanadashboard 与调查入口
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/probeSLI 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。

Alerting practices

本章把 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 bound

first 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 interval

route 要用 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 time

correctness 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/deprecation

orphaned 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 mix

metamonitoring

监控系统也会失败:

  • 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-end

Prometheus alerting practices 也建议用贯穿 PushGateway/Prometheus/ Alertmanager/email 的 blackbox 测试,而不是只盯每个组件进程。Pigsty v4 中要 把这个思想映射到 VictoriaMetrics/VMAlert/Alertmanager。

分类矩阵

signalclassroute例子
user event bad ratiosymptompage/ticket by burnavailability
data invariant mismatchintegritypageduplicate/cross-tenant
WAL distancecausedashboardreplication diagnosis
pool queuecausedashboardlatency diagnosis
CPUcausedashboard/ticketcapacity/diagnosis
days-to-fullcapacityticketdisk/storage
notification canary overduemetamonitoringpageblind 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 needed

validator 会故意把它的 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 first

rule 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 与变更治理 · 返回本章目录 · 下一节:证据、审计与合规 · 查看全书目录 · 查看索引中心

最后更新于