当你面对一台”系统很慢”的服务器时,很多人会凭直觉运行自己熟悉的几个命令——top、iostat、free——然后根据看到的数字猜测问题所在。这种做法完全依赖于你恰好知道哪些工具,得到的系统视图可能是不完整的,而你甚至不知道自己遗漏了什么。

监控方法论领域有三个常被并列的名字,它们的关系可以用一张表说清:

方法论 指标 最适合的对象 提出者与出处
RED Rate、Errors、Duration 请求驱动的服务(API、网关、微服务) Tom Wilkie,2015(Weaveworks)
USE Utilization、Saturation、Errors 基础设施资源(CPU、内存、磁盘、网络) Brendan Gregg,2012
四大黄金信号 Latency、Traffic、Errors、Saturation 任意生产服务(全栈视角) Google《SRE》书,2016

四大黄金信号与 RED 方法(Tom Wilkie 提出)、USE 方法(Brendan Gregg 提出)不是竞争关系,而是在技术栈不同层的互补视角。

三者关系可以简洁概括为:

  • 四大黄金信号 = RED + Saturation + 区分成功/失败延迟
  • RED 的 Rate 对应 Traffic、Duration 对应 Latency、Errors 对应 Errors——RED 去掉了 Saturation,更适合请求驱动的微服务场景。
  • USE 的 Utilization 和 Saturation 合在一起对应黄金信号的 Saturation——USE 更适合基础设施层(CPU、磁盘、网络接口)的深度诊断。

成熟团队的典型做法是在服务层用 RED、在基础设施层用 USE、用黄金信号作为统摄两者的心智模型。

USE方法论简介

Brendan Gregg 是全球顶尖的性能调优专家(目前任职于 Intel,曾在 Netflix、Sun、Joyent 等公司任职),也是《Systems Performance》《BPF Performance Tools》等经典著作的作者。他提出的 USE 方法论是系统性能分析和排障领域最经典、最实用的底层方法论之一。

USE 方法论的全称是 Utilization(使用率)、Saturation(饱和度)和 Errors(错误)。它是一种用于分析系统硬件资源(以及部分软件资源)性能的系统性框架,本质是一套用于构建性能检查清单(checklist)的方法——帮助你在分析服务器时快速、系统地识别资源瓶颈或错误。

USE 方法论的核心三要素

USE 方法论的全部内容可以用一句话概括:对于系统中的每一个资源,都检查以下三个指标。这句话里有两个关键概念——”资源”(Resource,所有物理服务器功能组件,如 CPU、磁盘、总线,也包括部分软件资源)和三项指标。下面逐项拆解。

Utilization(使用率)

  • 定义:资源在给定时间段内忙于服务工作的平均时间比例。
  • 特点:这是一个基于时间的指标。例如,如果 CPU 在过去 1 秒内有8 秒在执行任务,那么它的使用率就是 80%。常见表达方式是”时间间隔内的百分比”,如”磁盘运行在 90% 使用率”。
  • 注意:对于存储设备,使用率还可以指代”容量使用率”(例如磁盘空间用了 80%),但在 USE 方法论中,通常优先关注基于时间的 I/O 使用率。高使用率并不一定意味着系统存在性能瓶颈,但它是潜在瓶颈的指示器。

利用率陷阱:平均值会掩盖峰值

低利用率并不意味着无饱和。高利用率的突发(burst)可以在平均利用率较低的时间间隔内导致饱和和性能问题。Gregg 给出过一个真实案例:一位客户遇到 CPU 饱和(延迟)问题,但监控工具显示 CPU 使用率从未超过 80%。排障许久之后才发现,原因是监控工具报告的是 5 分钟平均值,而在此期间,CPU 使用率实际上在数秒内多次达到了 100%。这个案例的教训是:检查利用率时必须关注测量间隔。间隔越长,平均值越平滑,越容易掩盖短时突发。这正是后文解读规则中”70% 阈值”的由来之一。

Saturation(饱和度)

  • 定义:资源无法再处理更多工作的程度,通常表现为资源的排队长度或等待队列。
  • 特点:当资源达到 100% 使用率时,再增加工作负载就会导致饱和度上升。饱和度是判断性能瓶颈的最关键指标。例如,CPU 的运行队列长度、磁盘的 I/O 等待队列长度、网卡的丢包率(因为处理不过来而丢弃)。可测量为等待队列长度,或在队列上等待的时间。
  • 关联:饱和度通常与使用率正相关:使用率越高,越容易产生饱和。但对于某些支持并发处理的资源(如多核 CPU),使用率可能很高,但饱和度可能依然为 0——多个核心各自忙于工作,没有排队。

Errors(错误)

  • 定义:错误事件的发生次数。
  • 特点:这通常是系统出问题的直接表现。错误包括硬件故障(如磁盘坏道、网卡 CRC 校验错误)、协议错误(如 TCP 重传、后期碰撞)、甚至是操作系统层面的错误(如内存分配失败 OOM、上下文切换失败)。以标量计数表达,例如”网络接口有 50 次后期碰撞”。
  • 重要性:在排查性能问题时,检查错误应该放在第一位。因为错误往往会导致重试,从而进一步增加使用率和饱和度,形成恶性循环。USE Method 流程图将”检查错误”作为第一步,也是因为它通常最快、最容易被解读。

为什么需要 USE 方法论?

在没有系统方法论指导时,排查性能问题往往像”在黑暗中摸索”,工程师容易陷入两个误区:要么”凭感觉”只看几个熟悉的指标,要么盲目收集大量无用数据。

USE 方法论提供了一种自下而上、穷举式的排查策略,其价值体现在三个方面:

  • 全面性:强迫你列出系统的所有资源(CPU、内存、磁盘、网络、控制器、互连等),逐一检查,避免遗漏隐蔽的瓶颈。
  • 结构化:为每种资源提供明确的分析维度(U、S、E),避免”只看 CPU 使用率”这种片面做法。
  • 快速定位:高饱和度和高频错误通常直接指向性能瓶颈的根源。

与之对照的是大多数工程师默认使用的 Tools Method(工具方法):列出可用工具 → 列出工具提供的指标 → 列出解读规则。它有三个问题:完全依赖可用(或已知)工具,可能提供不完整的系统视图;用户不知道自己的视图不完整,问题将一直存在;遍历大量工具会分散对目标(找瓶颈)的注意力。USE 方法论则反其道而行:先迭代系统资源创建完整的问题列表,再搜索工具回答这些问题。未知区域被记录且其存在被知晓——曾经的”未知未知”(unknown unknowns)变成了”已知未知”(known unknowns),同时提供了高效寻找瓶颈和错误的策略。

常见资源的 USE 指标矩阵

Brendan Gregg 提倡为系统建立一张”USE 矩阵”表:给定资源列表,再考虑三种指标类型,就能系统地构建出检查清单的骨架。一台通用服务器上需要检查的物理资源包括六类:

  • CPUs:socket、核心、硬件线程(虚拟 CPU)
  • 内存:容量
  • 网络接口
  • 存储设备:I/O、容量
  • 控制器:存储控制器、网卡
  • 互连:CPU 互连、内存互连、I/O 互连(最经常被忽视的资源)

两个补充说明:

  • 其一,某些组件是两种类型的资源——存储设备既是服务请求的资源(I/O),也是容量资源(存储空间),两者都可能成为瓶颈。
  • 其二,硬件缓存(如 MMU TLB/TSB、CPU 缓存)被有意排除在 USE 方法论之外,因为它们在利用率升高时性能反而提高(缓存命中率越高越好),与其他资源”利用率高则性能降”的行为方向相反。

以下是常见硬件资源的 U、S、E 对应指标和 Linux 下的常用观测工具:

资源 Utilization(使用率) Saturation(饱和度) Errors(错误) 常用工具
CPU CPU 利用率(%user、%sys、%idle,每个 CPU 或系统范围平均值) 运行队列长度(Run queue length)、调度器延迟、负载平均值 可纠正的 CPU 缓存 ECC 事件、故障 CPU(需 OS+HW 支持) top、htop、mpstat、vmstat、perf
内存容量 已用内存占比、可用空闲内存 OOM 事件、匿名分页或线程交换、页面扫描 内存分配失败(失败的 malloc(),通常由于虚拟内存耗尽)、内存纠正错误(MCE) free、vmstat、sar、dmesg
网络接口 带宽吞吐量占最大带宽的比例(RX/TX 吞吐量 / 最大带宽) 网卡队列长度、丢包率(dropped、overruns)、TCP 重传率 接口错误(RX/TX errors)、CRC 错误、后期碰撞 ip -s link、ifconfig、sar -n DEV、ethtool
存储设备(I/O) 设备繁忙时间百分比(%util) I/O 等待队列长度、I/O 等待时间(await) 磁盘读写错误(”软”、”硬”错误)、超时重试 iostat -x、sar -d、dmesg、smartctl
存储容量 文件系统已用空间百分比 inode 使用率 文件系统只读、写入失败 df -h、df -i

注意:对于网络和存储,使用率往往表现为”吞吐量 / 最大带宽”,而不是简单的时间百分比。此外,部分更难的指标(存储控制器利用率、CPU/内存/I/O 互连的吞吐量与内存停顿周期等)取决于 OS 支持,Gregg 在实践中经常需要自己编写软件来获取——这也是实践中”最常见的问题通常用简单指标即可发现”(CPU 饱和、内存容量饱和、网络接口利用率、磁盘利用率应优先检查)的原因。

软件资源与云计算环境

某些软件资源也可以用类似方式考虑,通常适用于软件的较小组件(而非整个应用程序):

软件资源 Utilization Saturation Errors
Mutex 锁 锁被持有的时间 排队等待锁的线程
线程池 线程忙于处理工作的时间 等待线程池服务的请求数
进程/线程容量 系统有限进程/线程数的当前使用 等待分配 分配失败(如”cannot fork”)
文件描述符容量 类似上述,但针对文件描述符 等待分配 分配失败

数据库连接池、线程池、互斥锁都可以纳入这张矩阵。Gregg 的建议是不要过度纠结此类资源:如果指标有效就用,否则软件层面可以留给其他方法论(如延迟分析)。

在云计算环境中,软件资源控制可能限制或节流共享一个系统的租户,包括 hypervisor 或容器(cgroup)限制(内存、CPU、网络、存储 I/O),以及外部硬件限制(如网络吞吐量)。每个资源限制都可以用 USE 方法论检查,类似于物理资源。例如,”内存容量利用率”可以是租户的内存使用量 vs 其内存上限;”内存容量饱和”可以通过匿名分页活动看到——即使传统 Unix 页面扫描器是空闲的。

如何在实践中应用 USE 方法论?

Brendan Gregg 建议的排查步骤如下:

  • 资源清单:画出系统的架构图(功能块图),列出所有需要监控的资源。不仅是物理硬件,还可以包括软件资源(如数据库连接池、线程池、互斥锁)。功能块图展示了组件之间的连接关系,对查找数据流中的瓶颈特别有用;一个实用技巧是在图上标注每条总线的最大带宽,可以在未做任何测量之前就识别出潜在瓶颈。
  • 逐项排查:按照 E → S → U 的优先级(错误优先检查,因为通常更快、更容易解读),对每个资源进行检查。
  • 寻找瓶颈:发现饱和度高或错误频发的资源,这通常就是当前的瓶颈点。
  • 深入分析:针对发现的瓶颈,使用更高级的工具(如perf、eBPF/bpftrace、火焰图)去查明是哪个进程或哪段代码导致了该资源的瓶颈。

一个关键认知:系统可能同时存在多个性能问题,找到的第一个问题可能是”一个”问题但不是”那个”问题。每次发现都可用进一步方法论(工作负载特征分析、钻取分析)调查,然后根据需要继续迭代更多资源。最终你应有证据判断纠正措施是调整负载,还是调整资源本身。

典型场景示例

场景 A:系统响应变慢,但 CPU 使用率只有 30%

  • 传统思路:CPU 没满,不知道哪里出问题了。
  • USE 方法:检查 CPU 饱和度(vmstat发现 r 列运行队列很长)→ 检查磁盘饱和度(iostat 发现 %util 100% 且 await 很高)。
  • 结论:系统卡在 I/O 上,进程都在等磁盘,导致运行队列堆积。这正是”低利用率并不意味着无饱和”的典型体现——CPU 使用率低,但运行队列长说明 CPU 在等磁盘 I/O(iowait),瓶颈在存储设备。

场景 B:网络传输速度上不去

  • 传统思路:换根网线,或者重启网卡。
  • USE 方法:检查 Errors(ethtool -S发现大量 rx_missed_errors)。
  • 结论:网卡队列饱和,处理不过来导致丢包。解决方法:调整网卡 Ring Buffer 大小或开启多队列 RPS/RFS。丢包(dropped/overruns)正是网络接口饱和度的典型指标。

延伸案例:Apollo 登月舱

为了展示 USE 方法论的通用性,Gregg 将它应用于一个非常规系统——Apollo 登月舱制导系统。这个案例说明:只要一个系统有可识别的”资源”,USE 方法论就适用。

第一个资源是 Apollo Guidance Computer(AGC,阿波罗制导计算机):

指标 定义
AGC utilization 执行作业(非”DUMMY JOB”)的 CPU 周期数除以时钟频率(2.048 MHz)。该指标在当时似乎已被充分理解
AGC saturation “core set area”中的作业数量——7 组寄存器用于存储程序状态。允许作业被暂停(由”EXECUTIVE”程序,即现代所称的”内核”)。一旦耗尽,从饱和状态转为错误状态,AGC 报告 1202 “EXECUTIVE OVERFLOW-NO CORE SETS” 警报
AGC errors 许多警报已定义。除 1202 外,还有 1203 “WAITLIST OVERFLOW-TOO MANY TASKS”——另一种类型的性能问题:太多定时任务在返回正常作业调度前被处理

历史背景:1201(”NO VAC AREAS”)和 1202 警报在 Apollo 11 下降过程中著名地发生。第二个资源是交会雷达(Rendezvous Radar):Errors 为三种信号(”DATA NO GOOD”、”NO TRACK”、”SHAFT- AND TRUNNION-AXIS ERROR”),Utilization 为驱动电机忙于响应角度命令的时间。工作负载分析发现:交会雷达用于跟踪指令舱,即使登月舱正在下降也在中断 AGC——这是发现不必要工作(或低优先级工作)的典型案例。

解读规则与自定义清单

拿到指标数值后,如何判断是否异常?Gregg 给出的经验规则:

  • Utilization:100% 使用率通常是瓶颈的信号(需检查饱和度及其影响来确认);高使用率(超过 70%)就可能开始成为问题。原因有二:多秒或分钟级间隔测量的 70% 总使用率可能隐藏 100% 的短时突发;某些资源(如硬盘)在操作期间无法被中断,超过 70% 时排队延迟会变得更频繁和明显,而 CPU 几乎可在任何时刻被抢占,容忍度更高。
  • Saturation:任何程度的饱和都可能是问题(非零值即异常)。
  • Errors:非零错误计数器值得调查,特别是在性能差时仍在增加的错误。

反过来,”负面情况”同样有价值:低利用率、无饱和、无错误——这可以帮你快速缩小调查范围。实践中,读取每个资源与指标组合的数值可能非常耗时,你可能只有时间检查一个子集(CPU、内存容量、存储容量、存储设备 I/O、网络接口)。但即使只检查子集,USE 方法论的关键价值也在于:它让你意识到哪些内容没有被检查。对于自定义检查清单,应包括三个要素:使用哪个 OS 工具或监控软件、读取哪个统计量、不可用指标标记为”?”。最终得到约 30 个指标,其中一些无法测量,一些难以测量——这本身就是对系统能力边界的认知。Gregg 已为 Linux、Solaris、macOS、FreeBSD 等多个操作系统发布了现成的检查清单,链接见文末参考文献。

USE 方法论的局限性

USE 是一个强大的底层方法论,但它并不是万能的:

  • 只关注资源,不关注应用逻辑:USE 只能告诉你”CPU 被耗尽了”或”磁盘满负荷了”,但不能告诉你”为什么这段代码这么慢”。解决应用层延迟问题,通常需要结合 RED 方法(Rate、Errors、Duration,主要针对微服务)或使用火焰图进行代码级剖析。
  • 适用人群与延迟方法论的分界:延迟方法论(如 Method R)可以接近发现 100% 的问题,但如果不熟悉软件内部,会花费更多时间,更适合数据库管理员或应用开发者;USE 方法论则更适合初级或高级系统管理员——他们的职责范围包括 OS 和硬件。
  • 不涉及容量规划:USE 是排障和分析当前状态的利器,但对于未来的容量规划,还需要结合历史趋势和业务模型。
  • 盲区:对于非资源密集型的性能问题(如锁竞争导致的延迟,CPU 使用率很低但延迟极高),USE 可能只表现为”饱和度(等待队列)”的上升,需要进一步使用专门的分析工具(如perf lock 或 eBPF 追踪锁原语)。软件资源的指标也常常难以获取。

RED 方法论简介

Tom Wilkie 是云原生可观测性领域的知名工程师,2015 年任职于 Weaveworks 时提出了 RED 方法论,2018 年随其创业公司 Kausal 被 Grafana Labs 收购而加入 Grafana 任产品副总裁。RED 方法论是他最受欢迎的贡献之一,如今已成为微服务监控领域事实上的入门标准——常与 Brendan Gregg 的 USE 方法并称为”新服务上线要建的第一个监控面板”。

RED 方法论的全称是 Rate(请求速率)、Errors(错误)和 Duration(持续时间)。它是一种面向服务(而非硬件资源)的监控框架:对于架构中的每一个服务,都监控其请求的速率、错误和耗时分布。它的诞生动机很直接——USE 方法擅长回答”机器健康吗”,却难以回答”用户满意吗”;而微服务架构恰恰需要后者。

RED 方法论的核心三要素

RED 的检查对象不是 CPU、内存这类资源,而是”请求”(request)——它是从调用方视角观察一个服务的最小单位。一个请求从到达服务的那一刻起,只有三种可能的归宿:来了多少(Rate)、失败了没有(Errors)、花了多久(Duration)。三要素恰好覆盖了调用方能够观察到的全部表面。

Rate(请求速率)

  • 定义:服务每秒处理的请求数(requests per second,req/s),衡量服务的流量与需求量。
  • 特点:Rate 反映系统的负载水平,是容量问题的前导指标。它通常按服务、端点(handler)、状态码类别、调用方等维度聚合。Rate 变化需要与另外两个指标组合解读:流量上涨而 Errors 与 Duration 稳定,是健康的业务增长;流量上涨且 Duration 同步变长,则是容量告急的信号。
  • 注意:Rate 突增不一定来自真实用户——上游调用方的重试风暴、定时任务的批量调用都会推高流量,而这类”虚假流量”往往正是故障的放大器。埋点位置应放在服务入口(如 HTTP 中间件、gRPC 拦截器),并区分用户流量与内部调用。

Errors(错误)

  • 定义:失败请求的数量或所占比例(错误率),是用户痛苦的直接体现。
  • 特点:错误需要区分来源与类型:HTTP 5xx、gRPC 非 OK 状态码、业务层错误码各自指向不同的问题域。失败请求的延迟还应单独统计——连接被拒绝时快速失败(几毫秒)与内存不足时慢速失败(数秒)是完全不同的故障形态,混在一起统计会互相稀释。
  • 注意:错误应该最先检查(与 USE 方法中 Errors 优先的逻辑一致):错误往往触发客户端重试,重试推高 Rate,更高的 Rate 又制造更多错误与延迟,形成恶性循环。此外,错误率很低不等于没有问题——服务可能在静默降级(fallback 到缓存旧数据),需要结合业务指标判断。

Duration(持续时间)

  • 定义:请求耗时的分布(latency distribution),必须以直方图或多分位数(P50/P95/P99)表达,而不是单一平均值。
  • 特点:Duration 是三要素中最容易被实现错误的一个。真实生产流量的延迟分布几乎总是右偏的:大量快速请求聚集在左侧,一条缓慢的长尾拖向右侧。分位数各自回答一个具体问题——P50(中位数)是典型请求的体验,P95 是最慢的二十分之一的体验,P99 是最慢的百分之一的体验。
  • 注意:平均值会同时掩盖两端:一个平均 104ms 的服务,P50 可以是 30ms,P99 却高达 1229ms。对于每秒处理上千请求的服务,P99 意味着每秒都有十个请求经历秒级等待——平均数永远看不到这批用户。

这个图与 USE 方法论中”5 分钟平均值掩盖 100% 利用率峰值”的案例是同一个教训的不同侧面:单一汇总数字(平均值)天然适合掩盖分布的两端,而监控恰恰最关心两端。在 Prometheus 中,这意味着 Duration 要用 histogram 指标类型(带 le 标签的桶)而不是预先算好的单一数值。

为什么需要 RED 方法论

RED 方法的诞生有一个具体的起点:2015 年,Weaveworks 的一位新员工问 Tom Wilkie”你的监控哲学是什么”。他发现自己无法用一句话回答——于是把答案提炼成了三个指标。而他当时明确表示,彼时流行的 USE 方法并不适用于这个场景:

“USE 方法并不真正适用于服务,它适用于硬件、网络、磁盘这类东西。我们想要的是一种面向微服务的监控哲学,于是就有了 RED 方法。”——Tom Wilkie

这背后是微服务架构带来的监控范式转变。传统三层架构(负载均衡 → 应用服务器 → 数据库)中,监控对象数量少、变化慢,以主机为核心组织监控数据足够用。微服务架构则让”部件”数量增长了数量级,且任何组件可能在一天中的任意时刻被部署、扩缩容、替换。Tom Wilkie 在 2016 年 GOTO 大会的演讲中把这一点讲得很透:

“在旧世界里,你监控系统的主键是主机(host)指标;在新世界里,主键应该是应用服务(application services)。”

此外,把 USE 方法套用到服务层面会遇到大量语义模糊:内存的利用率算不算缓存?内存的”错误”是什么、怎么数?而 RED 把问题域换成请求之后,三个指标在每个服务上都有清晰、可直接度量的定义。综合来看,RED 的价值集中在三点:

  • 一是用户视角——错误率直接对应页面加载失败,耗时直接对应”网站慢”,是客户满意度的良好代理指标;
  • 二是跨服务一致性——每个服务暴露同一组指标,让运维团队能规模化扩张,让工程师可以为自己没写过的代码值班;
  • 三是告警与 SLA 的地基——基于”每服务的 R/E/D 是否在 SLO 内”构建的告警天然与用户体验对齐,而非与某个技术阈值对齐。

还有一个容易被忽略的用法要点:RED 不应只孤立地应用到单个服务上,而是应用到整个系统——沿着请求从入口到最终响应的路径追踪这三项指标,这才是它对微服务排查的真正价值。

RED 指标矩阵与观测工具

给定服务列表,再套上三项指标,就得到 RED 的检查清单矩阵。下表同时给出 Prometheus 生态下的标准实现(PromQL)与常用工具:

指标 回答的问题 典型单位 PromQL 示例 常用工具
Rate 这个服务每秒处理多少请求? req/s sum(rate(http_requests_total[5m])) by (service) Prometheus、Grafana、OpenTelemetry
Errors 这些请求中多少在失败? 错误率(%)或失败数/秒 sum(rate(http_requests_total{status=~”5..”}[5m])) by (service) Prometheus、Grafana、日志系统(错误日志计数)
Duration 这些请求花了多久? 延迟分位数(ms) histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, service)) Prometheus(histogram)、Grafana、分布式追踪(Jaeger/Tempo)

这三条 PromQL 是 RED 在 Prometheus 上的标准落地写法,可直接组合成一个按服务分组的 RED 面板。几个实现细节:Rate 用 rate() 对计数器(counter)求每秒增量;Errors 通常进一步除以总请求得到错误率比例;Duration 用 histogram_quantile() 从直方图桶计算分位数,le 标签必须保留在聚合维度中,否则结果无意义。

埋点侧的常见选择:

  • HTTP 服务用中间件计数(如各语言的 Prometheus client library 暴露的http_requests_total 计数器与 http_request_duration_seconds 直方图);
  • gRPC 服务按方法与状态码计数;Java Spring Boot 用 Micrometer、Python 用 prometheus_client,OpenTelemetry 则可以在不手写埋点的情况下从链路追踪自动派生 RED 指标。

如何在实践中应用 RED

Brendan Gregg 建议的实践路径同样适用于 RED,可以概括为四步:

  • 盘点服务清单:画出系统架构图,列出所有服务及其调用关系——请求从哪里进、经过谁、到哪里出。这张图决定了 RED 面板的行数。
  • 统一埋点:为每个服务暴露同名、同语义的 R/E/D 指标(服务名作标签)。一致性比单点精细更重要。
  • 建 RED 面板:每个服务三行图(Rate、Errors、Duration 分位数),按服务分组;新服务上线即接入,成为默认配置。
  • 基于 SLO 告警:对错误率、P99 延迟设定与用户体验对齐的阈值(如错误率 > 1%、P99 > 500ms),而非盯 CPU 这类中间技术指标。

典型场景示例

场景 A:深夜告警——支付服务错误率从 0.2% 涨到 8%

  • 传统思路:登录支付服务的几台机器翻应用日志,在每秒数千行里大海捞针;机器本身毫无异常,CPU、内存全部正常。
  • RED 方法:打开 RED 面板看维度下钻——错误码全是 502(Bad Gateway),说明请求根本没打到上游;查看支付服务所依赖的第三方支付网关的 RED 指标,发现其 Errors 同步陡增而 Duration 正常。
  • 结论:根因是第三方网关故障,本服务行为正确,应触发熔断与降级预案而非重启自己的服务。机器指标全程”健康”,正是 USE 方法在此场景下失灵、RED 方法一击命中的典型。

场景 B:用户集体抱怨”网站慢”,但平均响应时间只有 104ms

  • 传统思路:看监控大盘,平均延迟 104ms,一切”正常”,于是回复”无法复现”;或者怀疑用户网络问题。
  • RED 方法:Duration 看分位数不看平均——P50=30ms,但 P99=1229ms,直方图呈右偏长尾;按端点维度下钻,发现长尾集中在某个查询接口。
  • 结论:尾部延迟才是用户抱怨的来源(每秒上千请求中,最慢的 1% 就是每秒十几个”卡住”的用户)。进一步用分布式追踪定位到该接口的慢调用,再配合 USE 方法检查该实例的资源饱和(连接池耗尽、GC 停顿),最终修复。RED 负责”哪里慢”,USE 负责”为什么慢”。

与 USE 方法配合使用

Tom Wilkie 本人对两者关系的概括是:”RED 关心你的用户是否满意,USE 关心你的机器是否满意——它们其实是同一个系统的两种视图,是互补的。” 实践中的分工很清晰:RED 面板挂在最外层,回答”用户体验是否劣化、劣化在哪个服务”;当需要回答”为什么”时,下钻到该服务所在节点的 USE 检查清单(CPU/内存/磁盘/网络的使用率、饱和度、错误)。上文排查流程图中的分叉点,就是这两种方法论交接的地方。

方法论的局限性

RED 是一个强大的服务侧方法论,但它同样不是万能的,至少有四条边界:

  • 不含饱和度:RED 看不到”服务有多满”。容量逼近上限时,最早的信号往往是饱和度(队列长度、资源配额水位)而非延迟;需要饱和度时要么补上第四个指标(即黄金信号),要么下钻 USE。
  • 告诉你”慢”,不告诉你”为什么慢”:RED 描述服务与调用方之间的契约,不描述履行契约的内部机制。定位根因需要 USE(资源维度)、分布式追踪与日志的配合——这正是两大方法论被并称”一枚硬币的两面”的原因。
  • 只适用于请求驱动型服务:批处理作业、流处理管道、定时任务没有”每秒请求数”的自然语义,需要改用任务耗时、积压量、处理速率等替代指标,硬套 RED 会得到无意义的三件套。
  • 实现层面的平均值陷阱:方法论本身要求 Duration 用分布表达,但最常见的落地错误恰恰是只存了平均值或单一分位数——分布信息一旦在埋点处丢失,后续任何查询都无法恢复。

四大黄金信号简介

2016 年,Google 的站点可靠性工程(Site Reliability Engineering, SRE)团队在《Site Reliability Engineering: How Google Runs Production Systems》一书的第六章”Monitoring Distributed Systems”中提出了”四大黄金信号”(Four Golden Signals)。该书的作者团队包括 Betsy Beyer、Chris Jones、Jennifer Petoff 和 Niall Richard Murphy,他们总结了 Google 多年大规模生产系统的监控实践经验。

四大黄金信号的本质定义只有一句话:如果你只能为一个用户面向的服务测量四个指标,就测这四个——Latency、Traffic、Errors、Saturation。 它们共同构成了”用户影响视角”(User Impact Lens):从用户角度出发的四点服务健康视图,独立于内部有多少指标亮绿灯。Google SRE 书的定位也很明确——黄金信号是一个黑盒(black-box)监控框架,只关注外部可见行为,即用户实际体验的内容。

核心四要素

四大黄金信号的每个指标都直接映射到用户体验的一个维度。以下逐项拆解。

Latency(延迟)

延迟是服务响应一个请求所需的时间。它衡量的是用户等待多久才能拿到结果——这是用户体验中最直接的”快”与”慢”。

主要特点

  • 必须用分位数(P50/P95/P99)而非平均值来度量。平均值被快速完成的多数请求主导,会系统性掩盖慢尾部。一个”95% 请求 50ms、5% 请求 10 秒”的服务,平均延迟不到 1 秒,看起来一切正常,但那 5% 的用户正在经历灾难。
  • 必须将成功请求与失败请求的延迟分开追踪。一个 HTTP 500 可能 1 毫秒就返回了,而正常请求需要 200 毫秒走完全部业务逻辑——如果混在一起计算,”快速失败”会让整体延迟看起来人为偏低,掩盖真实的慢问题。
  • P99 与 P95 应分别设置不同阈值告警:P99 捕获最差尾部体验,P95 更早捕获更广泛的退化。

注意

  • 延迟是滞后指标(trailing indicator)——它告诉你”用户已经感受到慢了”,而不是”即将变慢”。预测性指标是 Saturation。
  • 在多 Pod 环境中,Prometheus 的histogram_quantile 必须配合 sum by (le) 使用,否则跨实例分位数计算会返回破碎、重叠的错误结果。

Traffic(流量)

流量是系统正在处理的需求量。不同服务类型的”流量”定义不同:Web API 是每秒请求数(QPS),数据库是每秒事务数(TPS),消息队列是每秒消费消息数,流媒体是网络 I/O 或并发连接数。

主要特点

  • 流量为其他三个信号提供上下文。同样的错误率从1% 升到 1%,在正常 10 倍流量下和在峰值流量下,含义完全不同。
  • 流量骤降常被忽视,却是最隐蔽的故障信号之一。当上游某个依赖断了、不再发请求时,你的服务不报错、延迟正常,唯一可见的信号就是流量下降。分布式系统中最被低估的故障模式之一。
  • 应区分成功流量与错误流量。一个服务可能总流量稳定但成功流量骤降——错误请求顶替了成功请求的位置。

注意

  • 流量本身通常不直接作为告警阈值(”QPS > 1000″没有意义,除非你知道正常范围)。应基于滚动平均的百分比偏差来告警——比如”成功流量降到 1 小时平均值的 50% 以下”。

Errors(错误)

错误是请求失败的速率。它是最直接与用户痛感和 SLO 挂钩的信号。Google SRE 书将错误分为三类,这是黄金信号区别于 RED 方法的关键细节之一。

主要特点

  • 显式错误(Explicit):HTTP 5xx、连接超时、未处理异常——服务明确报告”我失败了”。
  • 隐式错误(Implicit):HTTP 200 但返回内容不正确或不完整——服务”说成功了”但实际没干对。这类错误最容易被遗漏,因为它们不会在传统的 5xx 监控中体现。
  • 策略性错误(Policy):技术上成功了,但违反了 SLO。比如 SLO 规定 99% 请求在 500ms 内完成,一个请求 8 秒返回了 HTTP 200——它是”成功”的,但违反了延迟 SLO,应计入错误预算消耗。

注意

  • 告警应基于错误率(错误数 / 总请求数),而非错误数绝对值。在高峰流量下 20 个错误可能是正常的,在低峰流量下 20 个错误可能意味着 100% 失败。
  • 大多数团队只监控显式错误。几乎没有团队将策略性错误接入告警——而这正是基于 SLO 的事件管理该发挥作用的地方。

Saturation(饱和度)

饱和度衡量系统距离其容量极限有多近——系统”有多满”。内存压力、连接池使用率、队列深度、磁盘空间、CPU 利用率都是饱和度的度量维度。在前三个信号中,饱和度是唯一的预测性(leading)指标,其余三个是滞后(trailing)指标——系统在达到 100% 之前就开始退化了。

饱和度背后有排队理论的数学支撑。在 M/M/1 排队模型中,平均响应时间 $W$ 与利用率 $\rho$ 的关系为:

$$W = \frac{1}{1 – \rho}$$

这意味着延迟随利用率呈非线性增长——利用率从 50% 到 70% 还算温和,但过了 70% 的”膝点”(knee),延迟急速攀升。Google SRE 书明确指出:”许多系统在达到 100% 利用率之前就会出现性能退化,因此设定利用率目标是必要的。” Brendan Gregg 在 USE 方法论中也强调:”70% 的总利用率可以掩盖短时 100% 的突发。”

与此相关的是 Little’s Law(利特尔法则):$L = \lambda \times W$,即系统中平均并发请求数 = 到达速率 × 平均停留时间。这不仅是理论公式——它是容量规划的实战工具。假设你的 API 每秒收到 2000 个请求、每个请求平均耗时 50ms,那么系统中同时有 $L = 2000 \times 0.05 = 100$ 个请求在途。你的线程池、连接池、内存都必须按这个数来配置,而不是仅凭 QPS 估算。

主要特点

  • 饱和度是前导指标——资源耗尽发生在错误出现之前,给你留出了反应窗口。
  • 度量饱和度需要知道每种资源的容量极限(连接池上限、内存总量、队列最大深度),并监控当前值与极限的距离。
  • 好的饱和度监控用变化率预测未来趋势(如 Prometheus 的predict_linear),而非仅告警当前值。

注意

  • 饱和度是四大信号中最难实现的。Latency、Traffic、Errors 都可以直接从请求维度度量,但 Saturation 需要你知道每种资源的容量上限——这一信息往往散落在配置文件、基础设施规格表和运行时参数中。
  • Saturation 告警应仅在预测到即将影响用户时才触发页面。CPU 80% 本身不值得叫醒工程师,但如果predict_linear 显示 4 小时内将突破 95%,那就是该动手的信号。

为什么需要四大黄金信号

现代监控的根本问题不是数据太少,而是数据太多。一个典型的生产环境会生成数千个指标和海量的时序数据,足以让工程团队忙上几周也找不到根因。团队的本能反应是”测量一切,之后再决定告警什么”——结果是告警疲劳:值班工程师对页面麻木、轮班倦怠、真正的事故被淹没在噪音中。

四大黄金信号反转了这个思路。它提供了一种自上而下、用户优先的过滤策略,核心价值有三:

  • 过滤噪音:从”用户是否受影响”出发,只对直接反映用户体验的指标告警。黄金信号告诉你”什么时候该叫醒人”——只有当问题已经发生且用户可见时。
  • 建立基线:流量信号定义了”正常”是什么样。没有基线,你无法判断一个数字是否异常;流量骤降作为最隐蔽的故障模式之一,只有建立了基线才能发现。
  • 预测未来:饱和度是唯一的前导指标。其他三个信号告诉你”用户已经受损”,饱和度告诉你”用户即将受损”——这是从被动救火到主动预防的关键转变。

Google SRE 书还做了一个重要区分:黑盒监控(black-box)测试外部可见行为,即用户实际体验的;白盒监控(white-box)检查系统内部行为。黄金信号是黑盒框架——这种纪律性确保只有问题既已发生又用户可见时才触发告警,这正是黄金信号可操作性的来源。

指标矩阵

以下是四大黄金信号的速查矩阵,包含每个信号的度量要点、典型 SLO、PromQL 示例和常用工具:

信号 回答的问题 度量单位 PromQL 示例 常用工具
Latency 用户等了多久? P50/P95/P99(ms 或 s) histogram_quantile(0.99, sum by (le) (rate(request_duration_seconds_bucket[5m]))) Prometheus + Grafana、OpenTelemetry、Jaeger
Traffic 系统在处理多少需求? req/s、TPS、msg/s、conn 数 rate(http_requests_total{status=~”2..”}[5m]) Prometheus、StatsD、Micrometer
Errors 多少请求失败了? 错误率(%)或错误数/s sum(rate(http_requests_total{status=~”5..”}[5m])) / sum(rate(http_requests_total[5m])) Prometheus、Sentry、ELK
Saturation 系统有多满?快到极限了吗? 利用率(%)、队列深度、连接池占比 predict_linear(node_filesystem_avail_bytes[1h], 4 * 3600) < 0 node_exporter、cAdvisor、kube-state-metrics

一个值得注意的标签差异:旧版 Prometheus exporter 使用 status 表示 HTTP 状态码,新版 OpenMetrics 合规 exporter 使用 status_code。使用前检查你的 exporter 约定并相应替换。

以下是告警实践中最常见的错误及正确做法对照:

信号 常见错误 正确做法
Latency 告警平均延迟 告警 P99/P95 分位数
Traffic 不区分成功流量与错误流量 仅对成功流量告警,基于滚动平均的百分比偏差
Errors 告警错误数绝对值 告警错误率(错误数 / 总请求数)
Saturation 仅告警当前利用率 用变化率预测(predict_linear)

实践步骤与场景示例

将四大黄金信号落地为实际监控体系,推荐以下四步路径:

  • 为每个用户面向服务建立四信号面板:每个服务一张标准面板,按 Latency、Traffic、Errors、Saturation 四行排列。OpenTelemetry 自动埋点可以几乎零成本地拿到前三项。
  • 定义 SLI 与 SLO:将 Latency 和 Errors 转化为 SLI(如”99% 成功请求在 200ms 内完成”),再设 SLO 目标(如”30 天滚动窗口内9% 请求成功”)。SLO 与 100% 之间的差距就是错误预算。
  • 基于 SLO 烧减速率告警:不是”错误率 > 1% 就告警”,而是”错误预算消耗速率超过正常 14 倍时告警”——这意味着一小时内烧掉了一周的预算。
  • 对 Saturation 配置预测性告警:用predict_linear 预测未来 4 小时的资源趋势,仅在预测到即将影响用户时触发页面。

以下是两个典型排障场景,展示黄金信号如何定位问题。

场景 A:连接池泄漏——延迟先于错误报警

  • 传统思路:值班工程师收到告警页面,发现错误率5%(低于 1% 阈值),CPU 60%(”正常”),找不到明显异常,在日志中翻找 30 分钟。
  • 黄金信号做法:Prometheus 在 14:03 触发 P99 延迟告警——延迟从 180ms 升至4 秒(8 分钟内),此时错误率仍低于 0.5%,数据库连接池显示 74%(低于 80% 阈值)。工程师注意到 Saturation 的变化率异常:连接池从 40% 在 20 分钟内攀升到 74%。检查最近部署记录,发现 13:55 的配置变更引入了连接泄漏。连接池达 91% 时回滚配置,14:44 服务恢复。总 MTTR 41 分钟,其中调查 38 分钟。
  • 结论:如果没有 P99 延迟告警,直到连接池 100% 耗尽、错误率飙升时才介入,MTTR 可能翻倍。黄金信号的核心价值是”延迟是饱和度的前导指示”——在错误爆发前就捕获到退化趋势。

场景 B:流量骤降——最隐蔽的故障

  • 传统思路:监控面板显示错误率 0%、延迟正常、CPU/内存正常。工程师认为”系统健康”,直到用户投诉或客服收到反馈才发现服务实际不可用。
  • 黄金信号做法:Traffic 信号配置了”成功流量降到 1 小时滚动平均的 50% 以下”告警。上游支付网关发生故障、不再向订单服务发请求时,订单服务自身不报错也不变慢——但成功流量在 5 分钟内骤降 60%。告警触发,工程师立即检查上游链路,发现支付网关实例健康检查失败、已被负载均衡器摘除。
  • 结论:流量骤降是分布式系统中最被低估的故障模式。当一个依赖断裂时,你的服务不报错、不变慢,唯一可见的信号就是没人来敲门了。没有 Traffic 信号的基线和偏差告警,这类故障只能靠用户投诉来发现。

方法论局限性

黄金信号虽是强大的监控框架,但有明确的边界:

  • 只检测不解释:黄金信号告诉你”用户受到了影响”以及”大概在哪个信号上”,但不解释”为什么”。P99 延迟飙升可能源于慢查询、连接池耗尽、下游依赖故障、糟糕的部署、内存泄漏、DNS 超时——仅凭四个信号无法区分。根因分析仍需 traces、日志和更深度遥测。
  • 调查间隙问题:平均故障检测时间(MTTD)3-5 分钟,平均缓解时间 3-5 分钟,但平均调查时间 30-35 分钟。瓶颈不在告警,而在告警触发后的上下文组装和假设验证——黄金信号不缩短这个间隙。
  • 不适用非请求驱动场景:批处理作业、流式管道、事件驱动架构没有清晰的”请求”概念。Traffic 和 Latency 在这些场景下的定义需要重新映射(如”每秒处理记录数”替代 QPS),Errors 可能需要从批次级别而非请求级别度量。
  • 饱和度的实现门槛高:需要知道每种资源的容量极限,这一信息在容器化、弹性伸缩环境中尤其难维护——Pod 的资源配额可能随部署而变。

参考文献 / 扩展阅读

0