# 阈值怎么定 · 从拍脑袋到有依据

> 「CPU > 80% 告警」这种阈值从哪来？通常是拍的。这一章给出定阈值的四种正当方法（SLO 倒推、历史基线、容量推算、趋势预测）、静态阈值的三个失效场景，以及一套可执行的决策流程。

- 作者：David（道雾轩）
- 专栏：指标采集与观测（https://daiw.org/manual/observability.md）
- 最后更新：2026-07-15
- 原文：https://daiw.org/manual/observability/alert-thresholds
- 转载与引用：请注明出处并附原文链接（https://daiw.org/about/copyright）

# 阈值怎么定 · 从拍脑袋到有依据

**“CPU > 80% 就告警”——这个 80% 从哪来的？**

诚实的答案通常是：**某个人某天拍的，然后被抄了五年**。这一章讲怎么定出**有依据**的阈值。

## 静态阈值为什么经常失效

<Callout type="warn">
  **“某指标 > 某常数”这种静态阈值，在三种场景下必然失效：**

  **① 规模变了，阈值没变**

  [第 2 部分讲过的磁盘例子](https://daiw.org/manual/observability/four-golden-signals)：`disk_used > 85%` 在 100GB 盘上意味着“还剩 15GB，可能几小时”，在 10TB 盘上意味着“还剩 1.5TB，能撑一周”。**同一个阈值，紧迫性差几个数量级。**

  **② 业务有周期，阈值没有**

  `qps < 100 告警`（检测流量异常）在白天是合理的，在凌晨 4 点会**每天准时误报一次**。业务天然有昼夜、工作日/周末、大促的周期，**而常数没有**。

  **③ 阈值定在“能承受”而非“该承受”**

  最隐蔽的一种：`P99 < 2s` 这个阈值，可能只是因为“我们现在就是 1.8s”。**它记录的是现状，不是目标**——于是系统慢慢劣化到 1.9s，你也不会知道，因为告警没响。**阈值变成了对现状的追认。**
</Callout>

## 四种正当的定法

<Callout type="info">
  **① 从 SLO 倒推（最正统）**

  ```
  业务承诺: "下单成功率 99.9%"
    ↓
  错误预算: 0.1%
    ↓
  告警阈值: 错误率 > 0.1%(或更精细:用[燃烧率](https://daiw.org/manual/observability/slo-burn-rate))
  ```
  **阈值来自承诺，不是来自现状。** 这是唯一“正确”的方法——[第 2 部分反复强调过](https://daiw.org/manual/observability/metric-ranges)。

  **② 从历史基线推（最实用）**

  ```text
  # 过去 7 天,这个指标的 P99 通常是多少?
  quantile_over_time(0.99, service:http_latency:p99[7d:5m])
  ```
  **先测量，再定阈值。** 定在“比正常情况明显差、但还没到用户抱怨”的位置。**注意：这个方法只能告诉你“什么是不寻常”，不能告诉你“什么是不可接受”**——那得靠 SLO。**两者要对齐**（[对不上时才是真问题](https://daiw.org/manual/observability/metric-ranges)）。

  **③ 从容量推（资源类）**

  ```
  压测得知: 单实例 500 QPS 时 P99 开始劣化
    ↓
  留 30% 余量: 350 QPS 告警
  ```
  **这适合有明确容量拐点的资源**。前提是你真的压测过——**没压测过就是在猜**。

  **④ 用趋势预测（增长类）**

  ```text
  # 按当前速度,4 小时内磁盘会满
  predict_linear(node_filesystem_avail_bytes{mountpoint="/"}[6h], 4*3600) < 0
  ```
  **这是[静态阈值的正确替代品](https://daiw.org/manual/observability/four-golden-signals)**：它告警的不是“现在多满”，而是“**还有多久出事**”——**后者才是你真正关心的**，而且它**自动适应盘的大小**。

  **`predict_linear` 是个被低估的函数**：任何“会持续增长直到撞墙”的东西（磁盘、[证书有效期](https://daiw.org/manual/observability/alert-thresholds)、配额、[Kafka lag](https://daiw.org/manual/observability/metric-ranges)）都该用它，而不是百分比阈值。
</Callout>

## 症状 vs 原因：该对哪个告警

这是告警设计里**最重要的一条原则**：

<Callout type="info">
  **优先对**症状**（用户能感知的）告警，而不是对**原因**（内部状态）告警。**

  | 类型 | 例子 | 该 page 吗 |
  | --- | --- | --- |
  | **症状** | 错误率 > 1%、P99 > 1s、[服务不可达](https://daiw.org/manual/observability/scrape-loop) | **✅ 该叫醒人** |
  | **原因** | CPU > 80%、内存 > 90%、连接池满 | **❌ 通常不该** |

  **为什么？**

  - **原因告警会漏** —— 你不可能列全所有可能的原因。CPU 正常、内存正常、磁盘正常，**但服务就是挂了**（比如死锁、下游炸了）。[第 0 部分讲的“未知的未知”](https://daiw.org/manual/observability/why-observability)——**基于原因的告警只能覆盖“已知的未知”**。
  - **原因告警会吵** —— CPU 90% 但用户毫无感知？[那可能只是资源被充分利用](https://daiw.org/manual/observability/use-method)。**你半夜爬起来，发现啥事没有。**
  - **症状告警不会漏** —— 不管什么原因，只要用户受影响，症状必然变化。**一条 SLO 告警，覆盖了所有你没想到的故障模式。**

  **那“原因”类指标有什么用？** [用来排障，不是用来 page](https://daiw.org/manual/observability/use-method)。它们该在**看板**上、在**排障手册**里，而不是在**电话里**。

  **例外：有预测性的饱和度可以告警**——但应该是**低优先级**（ticket 而非 page）：“磁盘 4 小时后会满”值得开个工单白天处理，不值得半夜叫人。**[第 2 部分说饱和度是唯一有预测性的信号](https://daiw.org/manual/observability/four-golden-signals)，这就是它的正确用法。**
</Callout>

## 分级：不是所有告警都该叫醒人

<Callout type="info">
  **一条告警最重要的属性不是阈值，而是“**它响了之后，人要做什么**”。**

  | severity | 含义 | 判据 | 渠道 |
  | --- | --- | --- | --- |
  | **page** | **立刻叫醒人** | **用户正在受影响，且需要人立刻介入** | 电话 / 短信 |
  | **ticket** | 工作时间处理 | 有问题但能等（如[磁盘 4 小时后满](https://daiw.org/manual/observability/alert-thresholds)） | 工单 |
  | **info** | 只记录 | 有参考价值，不需要行动 | 看板 / 日志 |

  **判据是一个尖锐的问题：“**如果这条告警在凌晨 3 点响，我会起床吗？如果不会，它凭什么是 page？**”**

  **每条 page 级告警都该能回答三个问题：**
  1. **用户在受影响吗？** —— 不是的话，不该 page。
  2. **需要人立刻做点什么吗？** —— 如果系统能自愈（重试、failover），不该 page。
  3. **有 runbook 吗？** —— 被叫醒的人知道该干嘛吗？**没有 runbook 的 page = 把一个人叫醒然后让他从零开始猜**。

  **三个都是“是”，才配当 page。** 这个筛子能滤掉大多数团队 80% 的告警——[下一章会讲为什么这么狠是对的](https://daiw.org/manual/observability/alerting-philosophy)。
</Callout>

## 低流量的陷阱（以及解法）

<Callout type="warn">
  **[第 2 部分提过的问题](https://daiw.org/manual/observability/red-method)：深夜只有 2 个请求，错了 1 个 = 50% 错误率 → 告警炸响。但这可能毫无意义。**

  **解法一：比率 + 绝对量双条件**
  ```text
  (service:http_errors:ratio_rate5m > 0.01)
  and
  (service:http_errors:rate5m > 0.1)      # 每秒至少 0.1 个错误才算数
  ```

  **解法二：用更长的窗口** —— `[30m]` 而非 `[5m]`，让样本量够。

  **解法三（最优）：用 [SLO 燃烧率](https://daiw.org/manual/observability/slo-burn-rate)** —— 它天然处理这个问题，因为它衡量的是“[错误预算消耗的速度](https://daiw.org/manual/observability/slo-burn-rate)”，而**低流量时消耗本来就慢**。[下一章讲。](https://daiw.org/manual/observability/slo-burn-rate)
</Callout>

## 决策流程

```mermaid
flowchart TD
    A["我想加一条告警"] --> B{"这是症状还是原因?"}
    B -->|"原因"| B1["→ 放看板,不告警<br/>(除非有预测性 → ticket)"]
    B -->|"症状"| C{"有 SLO 吗?"}
    C -->|"有"| C1["✅ 从 SLO 倒推<br/>→ 用燃烧率(下一章)"]
    C -->|"没有"| D["先看历史基线<br/>quantile_over_time"]
    D --> E{"基线 vs 期望?"}
    E -->|"基线达不到期望"| E1["❌ 别设告警<br/>→ 先去优化系统或重谈 SLO"]
    E -->|"基线正常"| F["定在'明显异常'处<br/>+ for 防抖 + 低流量保护"]
    F --> G{"凌晨 3 点会起床吗?"}
    G -->|"会"| G1["page(且必须有 runbook)"]
    G -->|"不会"| G2["ticket 或 info"]
    style B1 fill:#94a3b8,color:#fff
    style C1 fill:#22c55e,color:#fff
    style E1 fill:#ef4444,color:#fff
```

## 小结与下一章

**静态阈值三种必然失效**：[规模变了阈值没变（磁盘百分比）、业务有周期而常数没有（凌晨误报）、阈值定在“能承受”而非“该承受”（变成对现状的追认）](https://daiw.org/manual/observability/four-golden-signals)。**四种正当定法**：① **SLO 倒推**（[阈值来自承诺不是现状](https://daiw.org/manual/observability/metric-ranges)，最正统）；② **历史基线**（[先测量再定，但它只能说“什么不寻常”、不能说“什么不可接受”](https://daiw.org/manual/observability/metric-ranges)）；③ **容量推算**（要真压测过）；④ **趋势预测**（**`predict_linear` 是静态阈值的正确替代**——[告警“还有多久出事”而非“现在多满”，且自动适应规模](https://daiw.org/manual/observability/four-golden-signals)）。**最重要的原则：对症状告警，不对原因告警**——[原因会漏（覆盖不了未知的未知）、会吵（CPU 高但用户无感）；症状不会漏（一条 SLO 告警覆盖所有没想到的故障模式）](https://daiw.org/manual/observability/why-observability)；原因类指标[用来排障不用来 page](https://daiw.org/manual/observability/use-method)。**分级判据是“凌晨 3 点会起床吗”**，page 必须满足[用户在受影响 + 需要人立刻介入 + 有 runbook](https://daiw.org/manual/observability/alerting-philosophy)。低流量陷阱用[双条件 / 长窗口 / 燃烧率](https://daiw.org/manual/observability/slo-burn-rate)解。

有没有一种方法，能把“阈值”这个问题**从根上**解决？有——下一章。👉 [SLO 与燃烧率告警](https://daiw.org/manual/observability/slo-burn-rate)。

## 参考资料

- [1] Google《SRE Book》第 6 章（症状 vs 原因）、《SRE Workbook》第 5 章（Alerting on SLOs）。
- [2] Prometheus 官方文档：`predict_linear()`、Alerting rules;Rob Ewaschuk「My Philosophy on Alerting」。
- [3] 关联[常见指标范围](https://daiw.org/manual/observability/metric-ranges)、[饱和度的预测性](https://daiw.org/manual/observability/four-golden-signals)、[USE](https://daiw.org/manual/observability/use-method)。
