4. 黄金信号与四大指标:延迟、流量、错误、饱和度
Google SRE 在《SRE 工作手册》中提出的“黄金信号”(The Four Golden Signals)是面向用户与系统健康度的最核心可观测维度。任何 Metric 设计都应优先覆盖这四个象限:延迟(Latency)、流量(Traffic)、错误(Errors)、饱和度(Saturation)。本章通过具体实例,展示如何为每个信号设计可落地的 Metric。
4.1 四大信号定义与设计原则
| 信号 | 核心关注点 | 典型 Metric 示例 | 设计陷阱 |
|---|---|---|---|
| 延迟(Latency) | 请求处理耗时,区分成功与失败请求的延迟 | p50/p99/p999 响应时间(ms) | 仅用平均值掩盖长尾;未排除失败请求的虚假低延迟 |
| 流量(Traffic) | 系统承载的请求量级与速率 | QPS、RPS、带宽(bps)、活跃连接数 | 忽略流量季节性模式;未按路由/用户分片 |
| 错误(Errors) | 显式错误(HTTP 5xx)与隐式错误(业务失败) | 错误率(%)、错误计数、错误码分布 | 只统计显式错误;忽略超时导致的隐式失败 |
| 饱和度(Saturation) | 资源使用程度与排队压力 | CPU 利用率、内存使用率、队列深度、连接池占用 | 仅看利用率均值;未定义“饱和阈值” |
设计原则:每个黄金信号至少应包含 1 个计数型 + 1 个分布型 Metric。例如延迟同时上报 Histogram(分布)和 Counter(总耗时),错误同时上报 Counter(计数)和 Gauge(当前错误率)。
4.2 延迟(Latency)Metric 设计实例
延迟是用户体验最直接的反映。设计时需区分成功请求延迟与失败请求延迟,避免将超时失败的低延迟混入成功样本。
# Prometheus 示例:HTTP 请求延迟 Histogram
http_request_duration_seconds_bucket{le="0.005", status="2xx"} 1200
http_request_duration_seconds_bucket{le="0.01", status="2xx"} 3400
http_request_duration_seconds_bucket{le="0.05", status="2xx"} 8900
http_request_duration_seconds_bucket{le="0.1", status="2xx"} 9500
http_request_duration_seconds_bucket{le="+Inf", status="2xx"} 10000
http_request_duration_seconds_count{status="2xx"} 10000
http_request_duration_seconds_sum{status="2xx"} 452.3
- 分位数计算:使用
histogram_quantile(0.99, ...)得到 p99 延迟。 - 按端点拆分:增加
endpoint标签区分 /api/login 与 /api/search。 - 失败请求单独上报:使用
status="5xx"或status="error"标签,避免污染成功延迟分布。
常见错误:只上报平均延迟(avg)。平均延迟会完全掩盖 1% 请求耗时 10s 的长尾问题。必须使用分位数(p50/p99/p999)或直方图。
4.3 流量(Traffic)Metric 设计实例
流量反映系统当前负载压力,用于容量规划与异常检测。设计时需区分入口流量与出口流量,并按服务/路由/用户维度打标。
# 入口流量:每秒请求数(QPS)
# 使用 Rate 函数计算
rate(http_requests_total{service="checkout"}[1m])
# 出口流量:下游 RPC 调用量
rate(rpc_calls_total{service="checkout", downstream="payment"}[1m])
# 带宽流量:网络层字节数
rate(node_network_transmit_bytes_total{device="eth0"}[1m])
| 流量类型 | 典型 Metric | 标签建议 |
|---|---|---|
| HTTP 请求 | http_requests_total |
method, endpoint, status, service |
| 消息队列 | kafka_messages_in_total |
topic, partition, consumer_group |
| 数据库查询 | db_queries_total |
db_instance, query_type, table |
| 用户会话 | active_users_gauge |
region, tier, device_type |
4.4 错误(Errors)Metric 设计实例
错误信号需覆盖显式错误(HTTP 5xx、RPC 异常)与隐式错误(业务返回错误码、超时未响应)。设计时建议使用错误预算(Error Budget)概念。
# 显式错误率:HTTP 5xx 占比
sum(rate(http_requests_total{status=~"5.."}[5m]))
/
sum(rate(http_requests_total[5m]))
# 隐式错误:业务错误码计数
rate(business_errors_total{error_code="INSUFFICIENT_FUNDS"}[1m])
# 错误预算:SLO 为 99.9%,每月允许 0.1% 错误
error_budget_remaining = 1 - (total_errors / total_requests) / (1 - 0.999)
关键设计点:
- 错误 Metric 必须包含 error_code 或 status 标签,便于快速定位错误类型。
- 对于超时导致的隐式错误,建议单独上报
timeout_errors_total,不要混入正常请求计数。 - 错误率报警应使用 滑动窗口(如 5 分钟),避免瞬时抖动触发告警风暴。
4.5 饱和度(Saturation)Metric 设计实例
饱和度衡量资源接近极限的程度。设计时需定义饱和阈值,并关注排队长度而非仅利用率。
# CPU 饱和度:使用利用率 + 运行队列长度
node_cpu_seconds_total{mode="idle"} # 计算利用率
node_load1 # 1 分钟平均运行队列
# 内存饱和度:实际使用量 vs 限制
container_memory_working_set_bytes / container_spec_memory_limit_bytes
# 连接池饱和度:活跃连接数 / 最大连接数
db_connections_active / db_connections_max
# 磁盘 I/O 饱和度:I/O 等待时间占比
rate(node_disk_io_time_seconds_total[1m]) / rate(node_disk_io_time_seconds_total[1m] + rate(node_disk_io_time_weighted_seconds_total[1m])
| 资源类型 | 利用率 Metric | 饱和度 Metric(排队/等待) |
|---|---|---|
| CPU | CPU 利用率(%) | 运行队列长度(load average) |
| 内存 | 内存使用率(%) | OOM 事件计数、swap 使用量 |
| 磁盘 | 磁盘使用率(%) | I/O 等待时间、磁盘队列深度 |
| 网络 | 带宽利用率(%) | 丢包率、TCP 重传率 |
| 连接池 | 连接使用率(%) | 连接等待队列长度、超时拒绝计数 |
4.6 黄金信号关联分析:故障特征提取
单一信号往往无法定位根因,需要将四个信号交叉关联。以下 SVG 展示了典型故障场景下黄金信号的联动模式。
4.7 黄金信号 Metric 设计总结
- 延迟:使用 Histogram/Summary,按状态码和端点拆分,关注 p99 而非 avg。
- 流量:使用 Counter + Rate,按服务/路由/用户分片,关注季节性模式。
- 错误:使用 Counter + 错误码标签,区分显式与隐式错误,建立错误预算。
- 饱和度:使用 Gauge + 利用率/排队长度,定义饱和阈值,优先监控排队指标。
最佳实践:每个服务至少暴露 4 个黄金信号相关的 Metric 组。在仪表盘中将四个信号放在同一时间轴,便于故障时快速交叉对比。报警规则应基于信号组合而非单一指标,例如“延迟 p99 > 1s 且错误率 > 5%”比单独报警更精准。