要让Nginx故障转移状态真正“看得见”,需打通请求失败→重试→切换→成功全链路,核心是日志语义化、指标结构化、多维下钻;通过自定义failover_log、Prometheus+Loki双引擎、Grafana四类关键视图及分级告警实现。

要让 Nginx 故障转移状态真正“看得见”,不能只依赖 VIP 漂移或进程存活这类粗粒度信号,而需把“请求失败→重试→切换节点→最终成功”这一完整链路的数据采集、打标、关联和可视化全部串起来。核心在于日志语义化 + 指标结构化 + 多维下钻。
一、让每条日志能说清故障转移全过程
默认 access_log 无法体现重试行为,必须自定义日志格式,显式记录每次 upstream 尝试的目标、耗时和状态:
- 在 nginx.conf 的 http 块中添加:
log_format failover_log '$remote_addr [$time_local] "$request" ' '$status $body_bytes_sent ' '"$upstream_addr" "$upstream_response_time" "$upstream_status" ' '$request_time $msec';
- 在 server 或 location 中启用:
access_log /var/log/nginx/failover.log failover_log; - 关键字段含义:
$upstream_addr(逗号分隔的尝试地址列表)、$upstream_response_time(对应各次响应时间)、$upstream_status(对应各次状态码),三者位置严格对齐
二、用 Prometheus + Loki 双引擎支撑不同分析场景
单一存储难以兼顾实时聚合与原始链路还原,推荐组合使用:
-
Prometheus:通过
nginx-prometheus-exporter抓取 vts 或 stub_status,提取nginx_upstream_fails_total、nginx_upstream_backup_used等指标,用于统计“单位时间故障触发次数”“backup 节点调用占比” -
Loki:采集上面定义的
failover.log,利用 LogQL 做语义查询,例如:{job="nginx"} |~ `"504.*200"` | line_format "{{.upstream_addr}} → {{.upstream_status}}",快速定位跨节点恢复案例 - 两者通过相同标签(如
instance、upstream_name)打通,在 Grafana 中联动筛选
三、Grafana 看板必须包含的 4 类关键视图
不是堆砌图表,而是围绕“转移是否发生?是否成功?多慢?影响谁?”四个问题组织:
-
故障触发热力图:按
upstream_name和status分组,用 heatmap 展示 5xx 错误突增时段,叠加nginx_upstream_fails_total曲线确认是否同步上升 -
转移路径拓扑图:用 Grafana 的 FlowChart 插件,以
upstream_addr为节点,边权重为count_over_time({job="nginx"} |~ `"504.*200"[1h]),直观看出哪些 backup 关系被高频激活 -
有效转移耗时分布:用 Loki 查询成功转移请求(含至少一次 5xx 后接 200),计算
request_time - upstream_response_time[0]的 P95 值,避免把首次超时计入延迟 -
受影响 URI 排行榜:统计
request_uri维度下发生过失败再成功的请求数,排序后挂告警阈值,优先保障核心接口 SLA
四、告警规则要区分“可恢复”与“持续性”故障
避免误报和漏报,告警逻辑需结合状态持续时间和重试结果:
- 【瞬时抖动】不告警:
count by (upstream_name) (rate(nginx_upstream_status{code=~"50[24]"}[2m])) > 5且rate(nginx_upstream_status{code="200"}[2m]) > 0→ 视为已自动恢复,仅记录 - 【真实中断】立即告警:
sum by (upstream_name) (rate(nginx_upstream_fails_total[5m])) > 10且rate(nginx_upstream_backup_used[5m]) == 0→ 表明无 backup 可用或健康检查失效 - 所有告警携带
upstream_name、server_name、failed_requests_last_5m标签,便于跳转到对应看板视图


















