深色模式
指标体系建设:RED 与 USE 方法在 K8s 中的落地
摘要:本文面向生产 SRE / 平台工程师,把"该监控什么"从玄学变成检查清单。讲清 RED(面向请求驱动型服务)与 USE(面向每个资源)两套框架的定义、起源、适用边界、盲区和 PromQL 落地,给出用 Recording Rule 固化 SLI 的表达式,并说明如何用两者组合在 K8s 中覆盖服务侧与节点侧。适用 Kubernetes v1.28+。
适用版本与前提
- Kubernetes:v1.28+(cAdvisor、kube-state-metrics、node-exporter 均可作为 USE/RED 数据源)
- 指标源:应用 OTel/Prometheus 指标、node-exporter、kube-state-metrics、cAdvisor
- 前提:Prometheus 已部署并能抓取上述端点(见本分类
prometheus.md)
背景与问题
"可观测性"最大的坑不是"数据少",而是"数据太多却不知看哪个"。一个服务暴露上百个指标,值班时盯着哪个?答案不是"都看",而是用框架约束选择。RED 与 USE 就是两把尺子:一把量"用户爽不爽"(服务),一把量"机器是不是瓶颈"(资源)。两者都源自业界长期实践,且互不替代。
三句话记住
- RED = Rate / Errors / Duration,Tom Wilkie(Weaveworks,2015)提出,面向对象:服务。
- USE = Utilization / Saturation / Errors,Brendan Gregg(2012)提出,面向对象:资源。
- Grafana 官方文档原话:"USE tells you how happy your machines are, RED tells you how happy your users are." 告警应基于 RED(症状),USE 用于诊断(原因)。
核心概念
RED(服务侧)
| 维度 | 含义 | 为什么 |
|---|---|---|
| Rate | 每秒请求数 | 流量变化、容量规划基线 |
| Errors | 失败请求数/比例 | 用户是否看到失败 |
| Duration | 请求延迟分布(用直方图取分位) | 平均值掩盖慢尾,用户感知的是 p99 |
RED 的精髓是每个服务用同一套三个数字描述,一套 dashboard 模板覆盖整个微服务群,值班工程师没见过某服务也能读懂它的健康。它基本等于 Google SRE 的"四个黄金指标"去掉 Saturation。
USE(资源侧)
| 维度 | 含义 | 例子 |
|---|---|---|
| Utilization | 资源忙碌的时间占比 | 节点 CPU 1 - idle、内存占用率 |
| Saturation | 资源无法立即服务的排队工作量 | 运行队列长度、CPU CFS 节流、连接池等待 |
| Errors | 资源错误事件 | 磁盘 I/O 错误、丢包、OOM |
USE 像飞机紧急检查单:对每个资源(CPU、内存、磁盘、网络、乃至线程池、文件描述符、连接池)都查 U/S/E,能"用 5% 的 effort 解决约 80% 的服务器问题"(Brendan Gregg 原话)。
架构与原理:两者如何配合
一次事故:checkout p99 从 180ms 到 2.4s。RED 告诉你"用户受影响了",USE 扫一遍发现数据库主机 CPU 96%、运行队列 3 倍于核数、零硬件错误 → 瓶颈是数据库 CPU(很可能 13:55 上了无索引查询)。RED 单独关不了事故(不知道 why),USE 单独也会误报(找到忙 CPU 但不知用户是否在意)。两者组合才是闭环。
生产实践:用 PromQL 落地 RED
以 OpenTelemetry 的 HTTP 服务端延迟直方图(导出为 http_server_request_duration_seconds_*)为例:
promql
# Rate:每秒请求数
sum by (service_name) (
rate(http_server_request_duration_seconds_count{service_name="checkout"}[5m])
)
# Errors:5xx 比例(Duration 直方图无 code label 时,用独立错误计数器或 code label)
sum by (service_name) (
rate(http_server_request_duration_seconds_count{service_name="checkout", http_response_status_code=~"5.."}[5m])
)
/
sum by (service_name) (
rate(http_server_request_duration_seconds_count{service_name="checkout"}[5m])
)
# Duration:p99 按路由
histogram_quantile(0.99,
sum by (le, http_route) (
rate(http_server_request_duration_seconds_bucket{service_name="checkout"}[5m])
)
)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Duration 必须用分位,不是平均
平均值会把 1% 的 5s 请求淹没在 99% 的 50ms 里。用户感知的是慢尾(p99/p999)。直方图用 histogram_quantile,且 le 必须出现在 by 子句,否则分位计算错误。注意直方图分位本身有误差(桶边界插值),关键 SLO 用原生直方图(native histograms)更准 [版本相关] Prometheus 2.40+/原生直方图仍在演进。
生产实践:用 PromQL 落地 USE
来自 node-exporter 与 cAdvisor:
promql
# Utilization:节点 CPU 使用率
1 - avg by (instance) (
rate(node_cpu_seconds_total{mode="idle"}[5m])
)
# Utilization:Pod CPU 相对 request 的使用
sum by (pod, namespace) (
rate(container_cpu_usage_seconds_total{namespace="team-payments"}[5m])
)
/
sum by (pod, namespace) (
kube_pod_container_resource_requests{resource="cpu", namespace="team-payments"}
)
# Saturation:容器 CPU 节流(K8s 经典饱和度信号,利用率看不出来)
rate(container_cpu_cfs_throttled_periods_total{namespace="team-payments"}[5m])
# Saturation:节点运行队列长度(run queue)
node_load1 / count by (instance) (node_cpu_seconds_total{mode="idle"}) # [未实测] 近似核数
# Errors:磁盘 I/O 错误 / 网络收包错误
node_disk_io_errors_total + node_network_receive_errs_total1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
K8s 中 Saturation 比 Utilization 更该盯
容器 CPU 被 limits 限制时,throttling(节流)才是真正让用户请求排队的信号,而 container_cpu_usage 的利用率可能还很低。USE 的 S(饱和度)在 K8s 里用 CFS 节流、内存 working set 接近 limit、PID 数接近上限来表达,比单纯利用率更能预警"假健康"。
用 Recording Rule 固化 SLI
上述表达式昂贵(每次查询都重算),且 dashboard 与告警都要复用。用 Recording Rule 预聚合:
yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: red-use-recording
namespace: monitoring
labels:
prometheus: k8s
spec:
groups:
- name: red-recording
interval: 30s
rules:
- record: service:request_rate:ratio_rate5m
expr: |
sum by (service_name) (
rate(http_server_request_duration_seconds_count[5m])
)
- record: service:error_ratio:ratio_rate5m
expr: |
sum by (service_name) (
rate(http_server_request_duration_seconds_count{http_response_status_code=~"5.."}[5m])
)
/
sum by (service_name) (
rate(http_server_request_duration_seconds_count[5m])
)
- record: service:duration_p99:ratio_rate5m
expr: |
histogram_quantile(0.99,
sum by (le, service_name) (
rate(http_server_request_duration_seconds_bucket[5m])
)
)
- name: use-recording
interval: 30s
rules:
- record: node:cpu_utilization:ratio_rate5m
expr: 1 - avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m]))
- record: pod:cpu_throttled:rate5m
expr: rate(container_cpu_cfs_throttled_periods_total[5m])1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
Recording Rule 的收益
- 查询/告警只算一次,复用便宜;2. 表达式集中版本化,避免 dashboard 与告警各写一遍漂移;3. 命名约定(
level:metric:operation_window)让全栈一致。本文采用service:error_ratio:ratio_rate5m风格,可按团队约定调整。
验证
bash
# 1. Recording rule 是否生成序列
kubectl exec -n monitoring deploy/prometheus-k8s -- \
promtool query instant http://localhost:9090 'service:error_ratio:ratio_rate5m'
# 2. RED 三数是否齐全(无断点)
kubectl exec -n monitoring deploy/prometheus-k8s -- \
promtool query instant http://localhost:9090 'service:request_rate:ratio_rate5m{service_name="checkout"}'1
2
3
4
5
6
7
2
3
4
5
6
7
回滚与清理
生产危险
误删 PrometheusRule 会让告警/看板失依赖。删除前确认无告警引用该 record:
bash
kubectl delete prometheusrule red-use-recording -n monitoring
# 删除后相关 dashboard 面板会显示"no data",需同步更新1
2
2
故障排查
| 现象 | 根因 | 处理 |
|---|---|---|
| p99 计算为 NaN | by 缺 le 或 bucket 被 relabel 丢弃 | 确认 histogram_quantile 的 by 含 le;metric_relabel_configs 未 drop le |
| RED errors 恒为 0 | 错误未打 5xx / 指标无 code label | 明确错误定义(4xx 是否算?);用业务错误计数器 |
| USE CPU 高但用户无感 | 计划内批处理,属正常 | 不告警,放 dashboard;用 RED 决定要不要 page |
| 指标断点 | Pod 重启 / 抓取间隔 > 查询窗口 | 用 increase 替代 rate 跨重启;检查 target up |
| 基数爆炸 | label 含 user_id/pod 等高基数 | RED 聚合到 service_name 层级,不在 label 留动态值 |
性能、容量与成本
- RED 聚合到服务级即可,逐请求维度会产生海量序列。
- 直方图桶数影响精度与存储:原生直方图(native histograms)更省且更准,但
[版本相关]需 Prometheus 较新版本且后端兼容。 - Recording Rule 间隔(30s)与查询窗口需匹配;窗口过长(如
[30d])的 rule 很贵,长周期 SLI 用降采样或外部后端。
常见坑
- 延迟用 avg 不用分位 → 掩盖慢尾。
- 把 USE 高利用率直接 page → 误报训练团队忽略 pager。
- 4xx 当错误计入可用性 → 错误预算被"用户输错密码"吃掉;明确 SLI 成功定义。
- RED 套到批处理/流式任务 → "请求"不是自然单位,应改用吞吐/积压/成功率。
替代方案与权衡
- 四个黄金指标(Google SRE):RED + Saturation,伞形框架,适合用户面系统。
- USE 的软资源扩展:线程池、连接池、文件描述符、限流配额也是"资源",易漏;补进 USE 清单。
- USE 不适用于服务:Brendan Gregg 明确 USE 面向硬件/网络/磁盘,服务的"饱和度"由 RED 的 Duration 旁敲侧击。
FAQ
Q:RED 和 USE 哪个优先建? A:先 RED(用户视角、可告警),再 USE(诊断)。没有 RED 你不知道该不该叫人;没有 USE 你关不了事故。
Q:批处理任务怎么监控? A:RED 不合适,改用 throughput(吞吐)、lag(积压,如 Kafka consumer lag)、job success rate、duration。
参考资料
- Grafana 文档 - Dashboard best practices(RED/USE 说明),访问日期:2026-10-08。
- Tom Wilkie - The RED Method(GrafanaCon EU 2018),访问日期:2026-10-08。
- Brendan Gregg - USE Method,访问日期:2026-10-08。
- ClickHouse 工程博客 - RED vs USE methods,访问日期:2026-10-08。
- Prometheus 官方文档 - Recording rules,访问日期:2026-10-08。