3. 黄金指标概念

RED 方法(Rate、Errors、Duration)是 Tom Wilkie 在 2015 年提出的面向服务的监控模型,最初用于 Prometheus 微服务监控。在日志领域,RED 方法将三个核心信号从指标空间映射到日志事件空间,使 SRE 能够通过日志直接判断服务的健康状态,而无需依赖指标系统。

3.1 RED 三要素的日志语义

RED 要素 指标定义 日志映射 Loki 查询示例
Rate(速率) 每秒请求数(RPS) 日志行中标识请求开始或结束的事件计数 sum(rate({job="api"} |= "REQUEST_START"[1m]))
Errors(错误) 失败请求占比或值 日志行中 status >= 500 或包含 "ERROR" 级别的事件 sum(rate({job="api"} |= "status=5" [1m]))
Duration(持续时间) 请求处理耗时(P50/P99) 日志行中记录的响应时间字段,通过 LogQL 提取并计算分位数 quantile_over_time(0.99, {job="api"} | json | unwrap duration [5m])
关键认知: RED 方法在日志领域的核心价值在于——当指标系统不可用或数据粒度不足时,日志可以作为黄金指标的"备用数据源"。但日志的 RED 查询成本远高于指标,因此应优先使用指标系统承载 RED 监控,日志 RED 仅用于故障排查和根因分析。

3.2 RED 日志黄金指标架构

下图展示了 RED 方法在日志系统中的完整映射链路,从服务请求产生日志,到 Loki 摄取、查询,最终形成三个黄金信号的可视化面板。

RED 方法日志映射架构图 RED 方法在日志领域的映射架构 服务 A(API) 服务 B(订单) 服务 C(支付) 日志事件流(Log Stream) [REQUEST_START] [REQUEST_END] [ERROR] [status=200] [duration=123ms] Grafana Loki(日志存储与查询) Rate(速率) Errors(错误) Duration(延迟) Rate 面板 RPS / 请求趋势 Errors 面板 错误率 / 错误分布 Duration 面板 P50 / P99 延迟

3.3 Rate(速率)的日志实现

Rate 在日志中对应的是请求事件的发生频率。与指标系统直接计数不同,日志需要先通过 LogQL 过滤出代表请求开始或结束的事件行,再计算速率。

最佳实践: 在日志中嵌入明确的请求标记(如 REQUEST_START 或 REQUEST_END),避免使用模糊的文本匹配。标记越精确,Rate 查询的准确度越高。
# 计算每分钟请求速率(基于 REQUEST_START 标记)
sum by (service, endpoint) (
  rate({app="order-service"} |= "REQUEST_START" [1m])
)

# 计算每分钟请求速率(基于状态码存在性)
sum by (service) (
  rate({app="api-gateway"} |~ "status=\d{3}" [1m])
)

3.4 Errors(错误)的日志实现

Errors 在日志中对应的是错误级别事件或错误状态码的出现频率。日志的错误检测比指标更灵活,可以基于日志级别、状态码范围或错误关键字进行多维过滤。

错误检测方式 适用场景 LogQL 示例
日志级别过滤 结构化日志,明确 ERROR 级别 {app="payment"} |= "level=ERROR"
状态码范围 HTTP 服务,status >= 500 {app="api"} |~ "status=5[0-9]{2}"
异常关键字 非结构化日志,包含 exception/error {app="worker"} |= "Exception"
业务错误码 自定义业务错误码(如 err_code=4001) {app="order"} |= "err_code="
# 计算错误率(错误请求 / 总请求)
sum by (service) (
  rate({app="api"} |= "status=5" [1m])
) / sum by (service) (
  rate({app="api"} |~ "status=\d{3}" [1m])
) * 100
注意: 日志中的错误计数可能包含重复记录(如重试日志、堆栈跟踪多行)。建议在应用层对错误日志进行去重标记,或在 LogQL 中使用 | pattern 提取唯一错误 ID 进行去重。

3.5 Duration(持续时间)的日志实现

Duration 在日志中对应的是请求处理时间的数值提取与分位数计算。这是 RED 三要素中日志实现最复杂的一环,需要日志中包含结构化的耗时字段,并通过 unwrap 操作提取数值。

# 提取 duration 字段并计算 P99 延迟
quantile_over_time(0.99,
  {app="order-service"} |= "REQUEST_END"
  | json
  | unwrap duration [5m]
)

# 按 endpoint 分组计算 P50 延迟
quantile_over_time(0.50,
  {app="api-gateway"} |= "REQUEST_END"
  | json
  | unwrap duration [5m]
) by (endpoint)

3.6 RED 日志标签治理原则

为了高效支持 RED 查询,日志标签(Label)的设计必须遵循以下原则:

  • Rate 标签: 至少包含 service、endpoint、method,用于按服务维度聚合速率。
  • Errors 标签: 至少包含 status_code、error_type,用于按错误类型分类。
  • Duration 标签: 至少包含 duration 字段(作为日志行内的结构化字段,而非标签),避免高基数标签爆炸。
  • 公共标签: app、env、host、trace_id 作为所有日志的基座标签。
RED 标签治理结构图 RED 日志标签治理结构 日志标签集 Rate 标签 service, endpoint, method 基数:低(固定枚举值) Errors 标签 status_code, error_type 基数:中(有限状态码集合) Duration 标签 duration(行内字段) 基数:高(不推荐做标签) 公共基座标签:app, env, host, trace_id(所有日志必须携带)

3.7 RED 日志查询性能对比

RED 要素 查询复杂度 典型延迟 优化建议
Rate 低(仅过滤 + rate) < 1s 使用精确标记,避免正则
Errors 中(过滤 + 聚合) 1-3s 预聚合错误标签,减少扫描量
Duration 高(unwrap + 分位数) 3-10s 限制时间范围,使用 quantile_over_time 时避免过大窗口
实战建议: 在 Loki 中为 Duration 查询创建专用的记录规则(Recording Rules),每 5 分钟预计算 P50/P99 延迟并存储为指标,避免每次查询都扫描全量日志。这是 RED 日志监控从"可用"走向"高效"的关键一步。