路线图

07 四个黄金信号(Four Golden Signals)

星辉 2026-07-02 阅读 5 min 937 字 路线图
07 四个黄金信号(Four Golden Signals) 封面

概述#

面对一个完全陌生的服务,该监控什么?Google SRE 提出了"四个黄金信号"(Four Golden Signals)框架,让每个工程师都能在 15 分钟内搭建"够用"的监控基线。本章深入展开四种信号的定义、测量方法,以及与 RED/USE 方法论的配合,建立"看任何一个系统的第一眼该看什么"的肌肉记忆。

四个黄金信号不是凭空选的,是从"用户对服务的感知维度"反推出来的——用户只关心两件事:服务能不能用(错误)、用起来快不快(延迟)。运维还要关心:服务承受多大压力(流量)、还能撑多久(饱和度)。这四个维度构成了完整的"服务体检报告"。

本章聚焦方法论。Prometheus/Grafana/Loki 的部署配置见 DevOps 路线 Ch25-28。

一、四个黄金信号#

1. Latency(延迟)#

定义:处理一个请求所需的时间。区分"成功请求的延迟"和"失败请求的延迟"——失败请求通常返回很快(直接报错),如果和正常请求混在一起算平均,会掩盖真实的性能问题。

关键度量

  • P50 / P95 / P99 / P999 分位数(不用平均值)
  • 按接口粒度区分——整体 P99 好看不代表每个接口都好
  • 区分读操作和写操作的延迟
  • 区分成功请求和失败请求的延迟分布

为什么不用平均延迟:平均值把长尾吞掉。99% 请求 10ms + 1% 请求 10s → 平均 110ms(看起来还好),但 P99 = 10s(那 1% 用户在受苦)。

更隐蔽的问题是"失败请求拉低平均延迟"。假设 5% 请求超时 30s,95% 请求 200ms。平均 = (95×0.2 + 5×30) / 100 = 1.69s。看起来"延迟 1.7s 还能接受"。但如果只算成功请求,平均是 200ms——服务其实很快,只是 5% 用户在受苦。所以 Google SRE Book 强调:错误请求的延迟要和成功请求分开统计

PromQL 示例

promql
# P99 延迟(所有请求)
histogram_quantile(0.99,
  sum(rate(http_request_duration_seconds_bucket[5m])) by (le, job)
)

# P99 延迟(只算成功请求)
histogram_quantile(0.99,
  sum(rate(http_request_duration_seconds_bucket{status!~"5.."}[5m])) by (le, job)
)

# 慢请求占比(延迟 > 500ms 的请求比例)= 1 - 快请求占比
# le="0.5" 桶算出的是"≤500ms 的快请求占比",取 1 - 才是慢请求占比
1 - (
  sum(rate(http_request_duration_seconds_bucket{le="0.5"}[5m]))
  /
  sum(rate(http_request_duration_seconds_count[5m]))
)

延迟 SLI 的两种表达

  • 绝对值型:P99 < 500ms(更直观)
  • 比例型:99% 的请求 < 500ms(更贴近用户感受)

两者数学上等价,但比例型更适合做 SLO——它直接表达"多少用户满意"。

2. Traffic(流量)#

定义:服务承受的请求量。对 HTTP 服务是 QPS/RPS,对消息队列是消息速率,对数据库是查询数/连接数,对存储是 IOPS。

为什么重要

  • 流量是其他信号的分母——错误率 = 错误数 / 总流量,不看流量光看错误数会误判
  • 流量突增本身可能就是问题——DDoS、热点事件、上游重试风暴
  • 容量规划的基础数据
  • 流量分布异常是故障信号——某个接口流量突然涨 10 倍可能是上游 bug

关键度量

promql
# 总 QPS
sum(rate(http_requests_total[5m])) by (job)

# 按接口粒度
sum(rate(http_requests_total[5m])) by (job, handler)

# 按状态码分布
sum(rate(http_requests_total[5m])) by (status)

流量分析的常见场景

  • 流量突增:是营销活动、是上游重试风暴、还是 DDoS?
  • 流量下降:是上游故障、DNS 问题、还是节日效应?
  • 流量分布异常:某个接口突然占 80% 流量,可能是前端 bug 触发循环调用
  • 流量模式变化:周末和工作日的流量曲线应该不同,如果一样可能 cron job 配错了

3. Errors(错误)#

定义:请求失败的速率。分为两类:

  • 显式错误:HTTP 5xx、超时、连接拒绝
  • 隐式错误:HTTP 200 但返回的业务结果是错误的(如"支付成功"实际未扣款——这种更难发现)

关键度量

promql
# 显式错误率(5xx)
sum(rate(http_requests_total{status=~"5.."}[5m]))
/
sum(rate(http_requests_total[5m]))

# 含 429(限流)的错误率
sum(rate(http_requests_total{status=~"5..|429"}[5m]))
/
sum(rate(http_requests_total[5m]))

# 业务错误率(需要应用层埋点)
sum(rate(business_errors_total[5m]))
/
sum(rate(business_operations_total[5m]))

错误分类的细节

HTTP 状态码是否算错误说明
2xx成功
3xx重定向,正常
4xx(除 429)客户端错误,不算服务失败
429限流是服务端容量问题
499(客户端断开)多因服务端太慢导致客户端放弃,计失败
5xx服务端错误
超时服务无响应
连接拒绝服务不可用

隐式错误需要通过合成监控(probe)或业务层指标来捕获,纯 HTTP 状态码检测不到。这是 SLO 监控最容易遗漏的一类——一个返回 200 但内容为空的接口,对用户来说就是坏的。

错误率告警的陷阱:低流量服务错误率会剧烈波动。10 个请求里 1 个失败 = 10% 错误率,但这可能只是正常概率事件。需要结合流量绝对值判断——流量 < 10/min 的接口错误率告警意义不大。

4. Saturation(饱和度)#

定义:服务"有多满"——资源使用占总能力的比例。是最容易被忽视但最关键的信号。

需要度量的不是"用了多少",而是"还有多少余量"

资源类型饱和度指标说明
CPUCPU throttle 比例不是使用率——throttle 意味着被限制
内存OOM kill 次数、swap 使用不是使用率——OOM 才是真正的饱和
磁盘 I/Oiowait、队列深度不是 IOPS——队列深度才反映"排队"
网络丢包率、TCP 重传率不是带宽——丢包才反映"拥堵"
应用层线程池队列长度、连接池等待数队列长度 > 0 就是饱和
K8sPod 因资源不足 Pending 次数Pending 就是饱和
数据库连接池使用率、慢查询数慢查询堆积就是饱和

为什么饱和度重要:饱和度是"滞后指标"——CPU 使用率 90% 时服务可能还 OK,但饱和度 80% 意味着很快就没有余量应对流量波动。在达到使用率上限之前,饱和度就发出预警。

使用率 vs 饱和度的区别

  • 使用率:资源被使用的比例(CPU 80%)
  • 饱和度:资源无法立即服务请求的程度(队列长度、等待时间)

CPU 使用率 80% 但没有 throttle、没有队列 = 不饱和。CPU 使用率 60% 但 throttle 严重 = 饱和。饱和度才是性能问题的直接原因。

PromQL 示例

promql
# CPU throttle 比例
sum(rate(container_cpu_cfs_throttled_seconds_total[5m]))
/
sum(rate(container_cpu_cfs_periods_total[5m]))

# 内存使用率(接近 limit)
sum(container_memory_working_set_bytes)
/
sum(kube_pod_container_resource_limits{resource="memory"})

# Pod Pending
sum(kube_pod_status_phase{phase="Pending"})

# 连接池使用率(需应用埋点)
sum(db_connection_pool_active)
/
sum(db_connection_pool_max)

二、RED 方法:微服务监控的最小集#

RED 是 Tom Wilkie(Grafana Labs)提出的微服务监控方法论,可以看作黄金信号在微服务场景下的精炼版:

维度含义覆盖的黄金信号PromQL
Rate(请求率)每秒请求数对应 Trafficsum(rate(http_requests_total[5m])) by (job)
Errors(错误率)失败的请求比例对应 Errorssum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m]))
Duration(耗时)请求的 P99/P95 延迟对应 Latencyhistogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, job))

RED 的使用场景:每个微服务都应该有 RED 面板。它是"请求驱动型服务"的监控最小集——如果一个服务要对外提供 API,那 Rate/Errors/Duration 就是它最基本的体检报告。

RED 不覆盖什么:饱和度(Saturation)。所以 RED 方法需要搭配 USE 方法来覆盖资源层面。

RED 面板的标准布局

text
Row 1: 服务级总览
  - QPS(Rate)
  - 错误率(Errors)
  - P99 延迟(Duration)

Row 2: 按 endpoint 分解
  - 各 endpoint 的 QPS
  - 各 endpoint 的错误率
  - 各 endpoint 的 P99 延迟

Row 3: 错误详情
  - 按状态码分布
  - 按错误类型分布

三、USE 方法:硬件资源的"体检报告"#

USE 是 Brendan Gregg(Netflix)提出的资源监控方法论,面向 CPU、内存、磁盘、网络等物理/虚拟资源:

维度含义问题
Utilization(使用率)资源用于工作的平均时间占比"用得多凶"
Saturation(饱和度)排队等待资源的工作量"排多长的队"
Errors(错误)资源的错误事件计数"有什么坏了"

Redis 示例

维度指标
Utilization内存使用量、CPU 使用率
Saturation连接数达到 maxclients 的百分比、慢日志
Errors拒绝的连接数、后台 save 失败

MySQL 示例

维度指标
UtilizationCPU 使用率、Buffer Pool 命中率
Saturation活跃连接数 / max_connections、慢查询数
ErrorsAborted connects、Replication lag

什么时候用 USE

  • 系统出现性能问题,但 RED 面板看不出异常 → 可能是底层资源瓶颈
  • 做容量规划前,先看资源趋势
  • 新机器/新节点上架后的基线采集
  • 性能压测时的资源监控

USE 方法覆盖的资源类型

  • CPU
  • 内存
  • 磁盘 IO
  • 网络
  • GPU(AI 工作负载)
  • 应用层资源(线程池、连接池、锁)

四、三个框架配合使用#

text
              ┌──────────────┐
              │  黄金信号     │  ← 总框架(延迟/流量/错误/饱和度)
              └──────┬───────┘
        ┌────────────┼────────────┐
        ▼            ▼            ▼
   ┌─────────┐ ┌─────────┐ ┌─────────┐
   │  RED    │ │  USE    │ │ 自定义  │
   │(服务层)│ │(资源层)│ │(业务层)│
   └─────────┘ └─────────┘ └─────────┘

排障时的套用顺序

text
黄金信号发现异常 → RED 定位到具体服务接口 → USE 排查资源瓶颈
  1. 看黄金信号 Dashboard:延迟变高了,还是错误率升了?
  2. 如果延迟高 → 用 RED 面板定位是哪个接口的 P99 在涨
  3. 如果错误率升 → 看错误分布(5xx 类型、是否来自特定上游)
  4. 排除业务逻辑问题后 → 用 USE 看资源层:CPU throttle?内存压力?磁盘 IO 堵塞?
  5. 用链路追踪定位到具体 span → 拉对应日志看根因

实战案例:一次延迟告警的排查

text
1. 黄金信号面板:P99 延迟从 200ms 升到 1.5s
2. RED 面板:发现是 /api/orders 接口的 P99 在涨
3. USE 面板:CPU 使用率正常,但 CPU throttle 比例 30%
4. 链路追踪:/api/orders 的 trace 显示 DB 查询耗时从 50ms 涨到 800ms
5. 日志:DB 慢查询日志显示一条新 SQL 没走索引
6. 根因:某次发布引入了 N+1 查询

整个排查 5 分钟,因为每一层都有对应的信号和下钻路径。

五、白盒监控 vs 黑盒监控#

白盒监控(White-box Monitoring)#

基于系统内部暴露的指标:应用吐出的 Prometheus metrics、日志里的结构化字段、链路追踪的 span。

优点:细粒度、能定位根因、有历史趋势

缺点:只有你预先想到去监控的才能看到

黑盒监控(Black-box Monitoring)#

外部模拟用户行为来探测:HTTP probe、TCP 端口检查、合成事务。

优点:检测到的是用户实际感受到的、能发现"未知的未知"

缺点:只知道"有问题",不知道"为什么有问题"

SRE 的互补策略#

两者必须同时存在:

text
白盒:Prometheus metrics → SLO 告警、Error Budget、性能分析
黑盒:Blackbox exporter / cuj-prober 合成监控 → 存活检测、兜底告警

实战案例(A 旗舰可观测性体系)

  • 真实流量监控(Istio istio_requests_total)覆盖有用户流量时的场景
  • 合成监控(cuj-prober 5 链路主动拨测)覆盖 7×24 兜底——半夜无流量时验证链路可用
  • 两者互补:合成做兜底基线,真实流量做 90% 真用户报错的来源
  • 前端 RUM(Real User Monitoring)补足"真实用户在浏览器里感受到什么"

黑盒监控的几个层次

层次工具检测什么
网络层ping、tcp ping主机可达
服务层blackbox-exporter HTTP probe接口返回 200
业务层合成监控(cuj-prober)完整用户旅程成功
前端层RUM(Grafana Faro)浏览器端真实体验

每一层覆盖不同的"未知未知"——网络层不知道接口是否正常,接口层不知道业务是否正确,业务层不知道前端是否有 JS 报错。

六、Dashboard 设计原则(从培养教材 M5 提取)#

分层结构#

text
L1 概览盘(Overview)  →  整个系统的健康,值班第一眼看
L2 服务盘(Service)   →  单服务详情(RED 面板)
L3 实例盘(Instance)  →  单 Pod/主机排障

从上往下下钻,不需要一屏看 50 个图。

L1 概览盘的内容(值班第一眼):

  • 全局错误率(按服务排序)
  • 全局 P99 延迟(按服务排序)
  • 关键 SLO 状态(绿/黄/红)
  • 当前活跃告警数
  • 流量趋势(最近 1 小时)

L2 服务盘的内容(深入单个服务):

  • RED 三件套
  • 按 endpoint 分解
  • 错误分布(状态码、错误类型)
  • 饱和度指标(CPU throttle、连接池)

L3 实例盘的内容(单机排障):

  • 单 Pod/节点的资源使用
  • 单 Pod 的日志流
  • 单 Pod 的链路追踪

每个图要能回答一个具体问题#

  • ❌ "因为有 CPU 指标所以画一张 CPU 图"
  • ✅ "这张图回答:CPU throttle 的 Pod 是哪些"

设计原则:

  • 每个图有明确的问题:不能因为"有这个指标"就画图
  • 优先用阈值着色:绿/黄/红让状态一目了然
  • 避免过度堆图:一屏 50 个图 = 没有重点
  • 关键指标放最显眼位置:左上角是 SLO 状态

从可观测性培养教材 M1-M6 建立的心智模型#

培养教材建立了一套完整的能力链路:

text
M1 遥测信号(原材料)
→ M2 采集管道(怎么采)
→ M3 存储查询(存哪、怎么查)
→ M4 告警与 SRE(什么该告)
→ M5 可视化方法论(怎么看)    ← 本章聚焦此层
→ M6 架构治理(怎么管)

本章的方法论(黄金信号/RED/USE)属于 M5 层——在 M1-M4 基础设施就绪后,回答"怎么读信号"。

排障下钻闭环(检验可观测性架构的标准)#

text
告警(症状/指标)
  → 概览盘定位异常服务
  → RED 看是慢还是错
  → exemplar/trace_id 跳到慢请求的链路
  → 定位到具体 span
  → 拉那个 span 的日志看根因
  →(需要时)profile 看到代码行

能不能走通这个闭环,是检验整套可观测性架构"接缝"设计得好不好的终极标准。每一跳都需要跨信号关联键——trace_id 必须在指标、日志、链路里都存在。

七、不同场景下的信号选取#

HTTP API#

  • 必看:RED(Rate、Errors、Duration)
  • 补充:饱和度(连接池、CPU throttle)
  • 黑盒:HTTP probe + 合成监控

消息队列消费者#

  • 必看:消费速率、堆积数、消费延迟
  • 补充:错误率(消费失败)、重启次数
  • 饱和度:消费者数量、单消费者处理时长

数据库#

  • 必看:QPS、慢查询数、连接数
  • 补充:复制延迟、锁等待
  • 饱和度:Buffer Pool 命中率、磁盘 IO

后台批处理任务#

  • 必看:任务成功率、执行时长
  • 补充:任务排队数、失败重试次数
  • 饱和度:worker 数量、队列深度

AI/ML 服务#

  • 必看:推理 QPS、推理延迟、推理错误率
  • 补充:GPU 利用率、模型版本
  • 饱和度:GPU 显存、请求队列长度

不同场景的"四个黄金信号"具体指标不同,但框架不变。理解框架比记住具体指标更重要——遇到新类型的服务,能推导出该看什么。

实战要点#

  1. 每个新服务必须至少配 RED:Rate、Errors、Duration 三个面板是最小监控集。没有 RED 面板的服务不算"已接入监控"。
  2. 饱和度不要只看 CPU 使用率。CPU throttle 比例比使用率更有意义——throttle 意味着被限制了。
  3. 黑盒兜底不可省略:死机开关(Watchdog)是最简单的黑盒——告警系统自己挂了要知道。
  4. Dashboard 少于 10 个图开始。一屏 50 个图 = 没有图在看——重点图放前面,其余收进"更多"折叠区。
  5. Prometheus 部署与 Dashboard 连接:Prometheus/Grafana 部署配置见 DevOps Ch25,Recording Rules 优化见 Ch28。
  6. 延迟要分开统计成功/失败请求。失败请求的延迟混入会扭曲整体延迟分布。
  7. 低流量服务的错误率告警要谨慎。10 个请求里 1 个失败 = 10% 错误率,但这可能只是统计噪音。
  8. 每个面板都要能下钻。看到全局 P99 高,要能点击进入按 endpoint 分解;看到 endpoint 高,要能点击进入单 trace。
  9. 建立"信号关联键":trace_id 必须在指标(exemplar)、日志、链路里都存在,否则下钻闭环会断。
  10. 饱和度指标要提前定义阈值。不要等饱和度 100% 才告警——80% 就该预警,留 20% 余量。

小结#

四个黄金信号(延迟/流量/错误/饱和度)是监控方法论的总框架。RED(服务层)+ USE(资源层)是落地的两套具体配方。

记住排障闭环:告警 → 概览盘定位异常服务 → RED 看是慢还是错 → 从 exemplar 跳到慢请求的链路 → 拉那个 span 的日志看根因 → 必要时看火焰图到代码行。这个闭环能走通,可观测性架构就合格了;走不通,就说明跨信号关联键没设计好,需要补强。

下一章讲告警工程——有了这些信号,哪些该响告警、怎么响、响给谁。