答案是通过在 Nginx access log 中记录 $upstream_next_count 变量来精准监控 proxy_next_upstream 触发的无感重试频率,结合 upstream_addr 变化与 upstream_response_time 阶梯增长判断真实重试,并用 awk 或 Prometheus 实时统计重试次数及原因。

要监控网关层因 proxy_next_upstream 触发的二次(或多次)无感重试频率,核心思路是:让 Nginx 在每次实际发生重试时,在 access log 中打上可识别标记,再通过日志采集与分析工具统计频次。这不是默认行为,需主动定制。
关键:用 $upstream_next_count 变量标识重试次数
Nginx 官方变量 $upstream_next_count(自 1.23.0 起稳定支持,OpenResty 及主流发行版已普遍内置)表示「当前请求被转发到 upstream 的第几个节点」——
- 首次请求 → 值为
0 - 第一次重试(换节点)→ 值为
1 - 第二次重试 → 值为
2
以此类推。它只在proxy_next_upstream真正生效并切换节点时递增,不因健康检查剔除、backup 启用等被动调度而增加,精准反映“无感重试动作”。
你只需在 log_format 中显式记录它:
log_format upstream_retry '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'upstream="$upstream_addr" '
'upstream_time=$upstream_response_time '
'next_count=$upstream_next_count '
'upstream_http_x_request_id=$upstream_http_x_request_id';
access_log /var/log/nginx/access_retry.log upstream_retry;✅ 效果:每条日志末尾出现
next_count=0(正常)、next_count=1(重试一次)、next_count=2(重试两次)等,一目了然。
区分“真实重试”和“伪重试”,避免误统计
有些场景看似重试,实则不属 proxy_next_upstream 行为,需过滤排除:
-
upstream_addr显示同一 IP:port 多次 → 可能是长连接复用或单节点 upstream,不是重试 -
next_count=0但upstream_response_time极高 → 是单次慢响应,未触发重试 -
upstream_addr切换但next_count仍为0→ 可能是ip_hash或least_conn调度导致,非proxy_next_upstream主动切换
真正有效的重试日志应同时满足:
安全更新和维护 CLI Proxy API(CPA)部署与配置。用于 CPA 镜像升级、配置变更、认证目录兼容修复、上线验证与回滚。适用于用户提到“CPA 更新/升级/配置改了/容器重建/回滚”等场景。
-
next_count > 0 -
upstream_addr明确变化(如10.0.1.10:8080, 10.0.1.11:8080) -
upstream_response_time呈阶梯式增长(如0.003, 0.042),说明前次失败后换节点
实时统计重试频率的实用方法
部署后,用标准工具即可快速出数:
-
每分钟重试请求数(含所有重试层级):
awk '$12 > 0 {count++} END {print "retry/min:", count/NR*60}' /var/log/nginx/access_retry.log -
按重试次数分组统计(看是否集中在 1 次 vs 多次):
awk '$12 > 0 {hist[$12]++} END {for (i in hist) print "next_count=" i ": " hist[i]}' /var/log/nginx/access_retry.log 结合 Prometheus + nginx-exporter(推荐生产):
自定义指标nginx_upstream_retry_count{upstream="backend", next_count="1"},用rate(nginx_upstream_retry_count[1m])直接看每秒重试率,告警阈值设为> 0.5即表示每两秒就有一起重试,需关注后端稳定性。
补充:加一层业务上下文,定位问题根源
单纯知道“重试多”不够,要关联原因。建议在日志中同时记录触发重试的具体错误类型:
map $upstream_http_content_type $retry_reason {
default "";
"~^text/html.*502" "502";
"~^text/html.*504" "504";
"~^application/json.*503" "503";
}
# 或更通用:用 $upstream_status(需开启 proxy_intercept_errors)再扩展 log_format:
... 'retry_reason=$retry_reason' 'upstream_status=$upstream_status'
这样就能回答:
▸ 是不是某台机器老返回 502?→ 查 upstream_addr + retry_reason=502
▸ 是不是超时集中爆发?→ 查 next_count=1 且 upstream_response_time > proxy_read_timeout
▸ 是不是健康检查没跟上?→ 查 next_count=1 但 upstream_addr 总在 A/B 间跳,C 却从不出现(说明 C 已被 max_fails 剔除但未恢复)
不复杂但容易忽略

















