# USE 方法 · 资源的三个信号，精髓在饱和度

> Utilization、Saturation、Errors —— Brendan Gregg 的资源监控方法论。这一章讲清三者的区别、为什么「饱和度」才是精髓（使用率 100% 不一定有问题，饱和度 > 0 一定有），并给出 CPU/内存/磁盘/连接池的具体 PromQL。

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

# USE 方法 · 资源的三个信号，精髓在饱和度

[RED 测服务](https://daiw.org/manual/observability/red-method)，**USE 测资源**。它由性能大师 Brendan Gregg 提出，针对**每一类资源**问三个问题：

| 信号 | 全称 | 问题 |
| --- | --- | --- |
| **U** | **Utilization** | 使用率：**忙的时间占比**（或已用容量占比） |
| **S** | **Saturation** | 饱和度：**排队的程度**——有多少工作在等 |
| **E** | **Errors** | 错误：这个资源报了多少错 |

**精髓在 S。** 这一章讲清为什么。

## 使用率 ≠ 有问题

<Callout type="info">
  **最反直觉、也最重要的一条：**使用率 100% 不一定有问题；饱和度 > 0 几乎一定有问题**。**

  想象一个收银台：
  - **使用率 100%** —— 收银员一刻不停在扫码。**这是好事！** 说明资源被充分利用，没浪费。只要**没人排队**，顾客体验完美。
  - **饱和度 > 0** —— **有人在排队**。这一刻起，顾客开始**等待**——延迟产生了。

  **使用率衡量“资源在忙吗”，饱和度衡量“有人在等吗”。用户感知的是后者，不是前者。**

  这解释了一个常见的错误认知：很多团队看到“CPU 90%”就紧张，看到“CPU 40%”就放心。但真相是：
  - **CPU 90% 但 load 很低、没有排队** —— 系统跑得很好，资源利用充分。**恭喜，你的钱花得值。**
  - **CPU 40% 但线程都堵在锁上** —— CPU 闲着，但请求全在排队。**用户体验已经崩了，而你的 CPU 面板一片绿。**

  **只看使用率会同时导致误报和漏报。** 这就是 USE 把饱和度单列为一个一等信号的原因——它是**最接近用户痛苦**的资源指标。
</Callout>

## 各类资源怎么测

USE 的用法是：**列出你所有的资源，给每个都填这三格**。

| 资源 | Utilization | Saturation ★ | Errors |
| --- | --- | --- | --- |
| **CPU** | 非空闲时间占比 | **run queue 长度 / load** | （罕见）机器校验错 |
| **内存** | 已用 / 总量 | **swap 换页、OOM kill 次数** | OOM |
| **磁盘 IO** | 设备忙时占比 | **IO 队列深度、await** | IO 错误 |
| **网络** | 带宽占比 | **丢包、重传、队列溢出** | 网卡错误 |
| **连接池** | 已用连接 / 上限 | **等待连接的线程数 / 等待时长** ★ | 获取连接超时 |
| **线程池** | 活跃线程 / 上限 | **队列里排队的任务数** ★ | 拒绝的任务数 |

<Callout type="info">
  **表里打 ★ 的那两行（连接池、线程池）最值得注意——它们是**应用层的资源**，而且是最常见的隐形瓶颈。**

  很多“服务变慢”的事故，机器指标全是绿的（CPU 30%、内存 50%、磁盘闲），但**数据库连接池满了**，所有请求都在排队等连接。这时：
  - **Utilization** = 100%（连接都被占着）
  - **Saturation** = 一堆线程在等 ← **这才是用户感受到的那 2 秒**
  - 而 CPU/内存/磁盘 **全部正常**

  **如果你只对机器资源做 USE、不对应用层资源做，这类故障你会完全瞎掉。** 连接池、线程池、队列、信号量、限流器——**任何“有容量上限、会被占用、会让人排队”的东西都是资源**，都该上 USE。

  **实战建议：连接池的“等待时长”是最有价值的单个指标之一。** 它直接等于“用户为了拿到一个连接而多等的时间”。很多连接池库（HikariCP、Go 的 `database/sql`）都能吐这个，**务必采它**。
</Callout>

## 具体 PromQL（可以直接抄）

基于 `node_exporter` 的常用查询：

```text
# ── CPU ──
# U:使用率(非 idle 时间占比)
1 - avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m]))

# S:饱和度 —— load 除以核数(> 1 表示有排队)
node_load5 / count by (instance) (node_cpu_seconds_total{mode="idle"})

# ── 内存 ──
# U:使用率
1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)

# S:饱和度 —— 换页速率(> 0 就该警觉)
rate(node_vmstat_pswpin[5m]) + rate(node_vmstat_pswpout[5m])

# ── 磁盘 IO ──
# U:设备忙时占比
rate(node_disk_io_time_seconds_total[5m])

# S:饱和度 —— 加权 IO 时间(反映队列深度)
rate(node_disk_io_time_weighted_seconds_total[5m])

# ── 网络 ──
# S:饱和度 —— 丢包
rate(node_network_transmit_drop_total[5m]) + rate(node_network_receive_drop_total[5m])
# E:错误
rate(node_network_transmit_errs_total[5m]) + rate(node_network_receive_errs_total[5m])
```

<Callout type="warn">
  **注意 CPU 饱和度那条：`node_load5 / 核数`。** load 是个**容易被误读**的指标：

  - Linux 的 load **包含 D 状态（不可中断睡眠，通常是等 IO）的进程**，不只是等 CPU 的。所以 **load 高不一定是 CPU 忙，可能是磁盘慢**——这是个经典的误诊来源。
  - `load / 核数 > 1` 只是**粗略**说明“排队了”。更准确的 CPU 饱和度应该看 **PSI**（Pressure Stall Information，`/proc/pressure/cpu`），它直接告诉你“**因为等 CPU 而损失的时间占比**”——这正是饱和度的精确定义。较新的 `node_exporter` 支持 `node_pressure_cpu_waiting_seconds_total`，**有的话优先用它**。

  ```text
  # 更好的 CPU 饱和度:PSI(因等 CPU 而停顿的时间占比)
  rate(node_pressure_cpu_waiting_seconds_total[5m])
  ```
</Callout>

## USE 的落地清单

<Callout type="info">
  **Gregg 给的用法是一张**表**，不是一堆面板：列出每个资源，逐格填。填不出来的格子，就是你的监控盲区。**

  ```
  资源          U        S        E
  ─────────────────────────────────
  CPU           ✅       ✅       -
  内存          ✅       ✅       ✅
  磁盘          ✅       ✅       ✅
  网络          ✅       ❓ ←盲区!  ✅
  DB 连接池     ✅       ❓ ←盲区!  ✅
  线程池        ❓       ❓ ←盲区!  ❓
  ```

  **这张表的价值在于它让“盲区”显式化。** 大多数团队做完这张表会发现：机器资源填得挺满，**应用层资源（连接池、线程池、队列）几乎全是问号**——而那恰恰是最常出事的地方。

  **先把 ★ 那几个饱和度补上，收益立竿见影。**
</Callout>

## RED 和 USE 怎么配合

```mermaid
flowchart TD
    A["告警:RED 的 D 涨了<br/>(服务变慢)"] --> B{"查 USE:哪个资源饱和了?"}
    B --> C["CPU 饱和?<br/>→ 扩容 / 优化热点"]
    B --> D["连接池饱和?<br/>→ 调池大小 / 查慢查询"]
    B --> E["磁盘饱和?<br/>→ 换盘 / 减 IO"]
    B --> F["都没饱和?<br/>→ 问题在下游:查下游的 RED"]
    style A fill:#ef4444,color:#fff
    style F fill:#3b82f6,color:#fff
```

<Callout type="info">
  **典型排障流：**[RED](https://daiw.org/manual/observability/red-method) 告诉你“**服务出问题了**” → [USE](https://daiw.org/manual/observability/use-method) 告诉你“**是哪个资源的锅**”。**

  注意最后那个分支：**所有资源都没饱和，但服务就是慢** → 说明瓶颈**不在本服务**，而在**下游**（数据库、依赖服务、外部 API）。这时你要去看**下游的 RED**——于是递归下去，直到找到那个真正饱和的资源。

  **RED 是“症状”，USE 是“病因”**；RED 沿调用链递归，USE 在每一跳落地。这两套配合，构成了一个**可机械执行的排障算法**——不用灵感，顺着查就行。
</Callout>

## 小结与下一章

**USE = Utilization、Saturation、Errors**，对**每一类资源**问这三个问题。**精髓是饱和度**：[使用率 100% 不一定有问题（资源充分利用是好事），饱和度 > 0 几乎一定有问题（有人在排队 = 用户在等）](https://daiw.org/manual/observability/use-method)——**只看使用率会同时误报和漏报**（[CPU 90% 无排队 = 很健康；CPU 40% 全堵在锁上 = 已崩但面板全绿](https://daiw.org/manual/observability/use-method)）。关键盲区是**应用层资源**（[连接池 / 线程池 / 队列](https://daiw.org/manual/observability/use-method)）——机器指标全绿而连接池排满是最常见的隐形事故，**连接池等待时长是最有价值的单个指标之一**。CPU 饱和度用 `load/核数` 只是粗略（[load 含 D 状态进程，高不一定是 CPU 忙](https://daiw.org/manual/observability/use-method)），**有 PSI 优先用 PSI**。USE 的用法是**一张表**，让[盲区显式化](https://daiw.org/manual/observability/use-method)。配合上：**[RED 是症状（服务出事了），USE 是病因（哪个资源的锅）](https://daiw.org/manual/observability/use-method)**；都没饱和 → 瓶颈在下游，递归查下游的 RED。

第三套方法论来自 Google SRE，和 RED 高度重叠但视角不同。下一章讲清它们的关系。👉 [四大黄金信号](https://daiw.org/manual/observability/four-golden-signals)。

## 参考资料

- [1] Brendan Gregg「The USE Method」及《Systems Performance》。
- [2] Linux PSI（Pressure Stall Information）文档；`node_exporter` 指标参考。
- [3] 关联[RED 方法](https://daiw.org/manual/observability/red-method)、[常见指标范围](https://daiw.org/manual/observability/metric-ranges)。
