要让 error_log 捕获 upstream timed out 并计算雪崩率,关键在于日志结构化与指标闭环:确保 error_log 级别≥error、避免配置覆盖;通过 upstream 字段映射服务名,用脚本提取结构化事件;结合 access_log 统计分母,滚动计算雪崩率(timeout_count/total_requests);同步采集后端 cpu、gc 等指标排除误判。

要让 error_log 真正捕获 upstream timed out 并用于计算雪崩率,关键不是“打开日志”,而是让日志具备可提取、可聚合、可关联的结构化能力,并建立从日志到指标的闭环链路。
确保 error_log 输出含完整上下文字段
Nginx 默认日志已包含必要信息,但需确认配置未被覆盖或截断:
- 检查
error_log指令是否启用且级别 ≥error(error_log /var/log/nginx/error.log error;) - 确认日志格式未被自定义覆盖——标准 error 日志天然含:
upstream地址、clientIP、request路径、server名、时间戳和错误码(如(110: Connection timed out)) - 避免在
location或server块中重复定义error_log导致路径/级别冲突
用 grep + awk 实时提取超时事件并打标服务维度
“upstream timed out” 日志本身不直接带服务名,需通过 upstream 字段反查配置映射:
- 先解析 Nginx 配置,建立
upstream name → 后端地址列表 → 服务名映射表(例如backend_api → 10.10.2.11:8001, 10.10.2.12:8001 → user-service) - 用脚本实时 tail 日志并提取关键字段:
tail -f /var/log/nginx/error.log | grep "upstream timed out" | awk '{print $NF, $1, $4, $12}'
其中$NF是 upstream 地址,$12是 request 路径,可用于归类接口粒度 - 结合映射表,将原始日志行转换为带
service=user-service, endpoint=/api/v1/profile, timestamp=...的结构化事件
定义雪崩率并用时间窗口滚动计算
雪崩率不是固定阈值,而是单位时间内超时失败请求占该服务总请求的比例:
- 分子 = 过去 60 秒内,该服务所有
upstream timed out事件数(按 upstream 名或后端 IP 聚合) - 分母 = 同一窗口内,该服务所有成功响应 + 超时失败的总请求数(需从 access_log 中提取,匹配相同 upstream 或 location)
- 公式:
avalanche_rate = timeout_count / total_requests,建议以 5% 为警戒线,≥15% 触发熔断告警 - 用 Prometheus + node_exporter + custom exporter 实现:写一个轻量脚本持续消费结构化超时事件,同时从 access_log 统计各 upstream 的请求总量,暴露为
nginx_upstream_avalanche_rate{service="order", endpoint="/pay"}
关联后端健康状态排除误判
单纯统计超时可能误判——若后端因 CPU 打满或 GC 卡顿导致响应慢,但连接未断,Nginx 不会报 upstream timed out,此时雪崩率偏低但实际已雪崩:
- 同步采集后端服务的
process_cpu_percent、jvm_gc_pause_seconds、thread_count等指标 - 当某服务
avalanche_rate突增,但其后端 CPU proxy_read_timeout 过短) - 反之,若
avalanche_rate未达阈值但后端thread_pool_active_count持续 100%,说明故障已发生但尚未触发 Nginx 超时,需提前干预











