如何利用 log_format 和 $upstream_addr 跟踪复杂后端环境中的请求路径?
- 内容介绍
- 文章标签
- 相关推荐
本文共计747个文字,预计阅读时间需要3分钟。
要简化这段伪原创内容,可以去掉一些技术性描述和重复的词汇,如下:
必须包含的关键 upstream 变量
仅记录 $upstream_addr 不够,需搭配以下变量才能还原完整流向:
-
$upstream_addr:真实转发目标(IP:Port),重试时按顺序逗号分隔,如10.0.1.10:8080,10.0.1.11:8080 -
$upstream_response_time:对应每次转发的响应时间,单位秒(毫秒精度),顺序与$upstream_addr严格对齐,如0.023,1.876 -
$upstream_status:每次转发返回的状态码,如200,502,可直接判断哪次成功、哪次失败 -
$upstream_http_x_backend_name(可选但推荐):由后端在响应头中返回的逻辑标识(如user-service-v2),便于跨机器统一识别服务名
定义清晰可读的 upstream 日志格式
在 http 块中定义专用格式,避免和默认日志混用:
log_format upstream_trace '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' '$upstream_addr $upstream_response_time $upstream_status ' '$upstream_http_x_backend_name $request_id';
注意:$request_id 加入后可用于关联后端日志,形成端到端追踪链路;$upstream_http_x_backend_name 需后端主动设置响应头 X-Backend-Name 才有值。
在 location 中启用并验证输出
在具体代理的 location 块中启用该格式:
location /api/ {
proxy_pass http://backend_cluster;
access_log /var/log/nginx/api_upstream.log upstream_trace;
}
触发一次请求后,检查日志是否出现类似内容:
192.168.3.5 - - [30/Apr/2026:06:40:22 +0800] "GET /api/user/123 HTTP/1.1" 200 342 "-" "curl/7.68.0" "10.0.1.10:8080,10.0.1.11:8080" "0.012,0.008" "200,200" "user-service-v2" e8a3f9b2c1d4e5f6a7b8c9d0e1f2a3b4;
若 $upstream_addr 出现多个地址且 $upstream_status 含非 2xx 值,说明发生了重试;若只有一组值且 $upstream_response_time 明显偏高,则问题大概率出在该节点本身。
用简单命令快速看流向分布
无需导入 ELK,用基础命令即可发现异常模式:
- 统计各后端被选中的次数:
awk '{print $12}' api_upstream.log | cut -d',' -f1 | sort | uniq -c | sort -nr(取首个地址,忽略重试) - 查某台后端是否集中返回 5xx:
awk '$14 ~ /5[0-9][0-9]/ && $12 ~ /10\.0\.1\.10/' api_upstream.log | head -5 - 定位慢请求源头:
awk '$13 > 2.0' api_upstream.log | awk '{print $12, $13, $14}' | head -10(找响应超 2 秒的记录)
这些操作直击请求流向本质,比翻 error.log 更快定位是配置、网络还是后端自身的问题。
本文共计747个文字,预计阅读时间需要3分钟。
要简化这段伪原创内容,可以去掉一些技术性描述和重复的词汇,如下:
必须包含的关键 upstream 变量
仅记录 $upstream_addr 不够,需搭配以下变量才能还原完整流向:
-
$upstream_addr:真实转发目标(IP:Port),重试时按顺序逗号分隔,如10.0.1.10:8080,10.0.1.11:8080 -
$upstream_response_time:对应每次转发的响应时间,单位秒(毫秒精度),顺序与$upstream_addr严格对齐,如0.023,1.876 -
$upstream_status:每次转发返回的状态码,如200,502,可直接判断哪次成功、哪次失败 -
$upstream_http_x_backend_name(可选但推荐):由后端在响应头中返回的逻辑标识(如user-service-v2),便于跨机器统一识别服务名
定义清晰可读的 upstream 日志格式
在 http 块中定义专用格式,避免和默认日志混用:
log_format upstream_trace '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' '$upstream_addr $upstream_response_time $upstream_status ' '$upstream_http_x_backend_name $request_id';
注意:$request_id 加入后可用于关联后端日志,形成端到端追踪链路;$upstream_http_x_backend_name 需后端主动设置响应头 X-Backend-Name 才有值。
在 location 中启用并验证输出
在具体代理的 location 块中启用该格式:
location /api/ {
proxy_pass http://backend_cluster;
access_log /var/log/nginx/api_upstream.log upstream_trace;
}
触发一次请求后,检查日志是否出现类似内容:
192.168.3.5 - - [30/Apr/2026:06:40:22 +0800] "GET /api/user/123 HTTP/1.1" 200 342 "-" "curl/7.68.0" "10.0.1.10:8080,10.0.1.11:8080" "0.012,0.008" "200,200" "user-service-v2" e8a3f9b2c1d4e5f6a7b8c9d0e1f2a3b4;
若 $upstream_addr 出现多个地址且 $upstream_status 含非 2xx 值,说明发生了重试;若只有一组值且 $upstream_response_time 明显偏高,则问题大概率出在该节点本身。
用简单命令快速看流向分布
无需导入 ELK,用基础命令即可发现异常模式:
- 统计各后端被选中的次数:
awk '{print $12}' api_upstream.log | cut -d',' -f1 | sort | uniq -c | sort -nr(取首个地址,忽略重试) - 查某台后端是否集中返回 5xx:
awk '$14 ~ /5[0-9][0-9]/ && $12 ~ /10\.0\.1\.10/' api_upstream.log | head -5 - 定位慢请求源头:
awk '$13 > 2.0' api_upstream.log | awk '{print $12, $13, $14}' | head -10(找响应超 2 秒的记录)
这些操作直击请求流向本质,比翻 error.log 更快定位是配置、网络还是后端自身的问题。

