必须通过OpenTracing或OpenTelemetry的Nginx插件(如nginx-opentracing或opentelemetry-nginx-module)将$request_id映射为标准trace header(如traceparent或uber-trace-id),而非仅用proxy_set_header透传X-Request-ID;否则Jaeger无法识别,链路必然断裂。

如何在 Nginx 中正确注入 $request_id 到 Jaeger 上报的 trace context 中
Jaeger 默认不识别 Nginx 的 $request_id,直接透传或拼接 header 无法让下游服务自动关联 trace。必须通过 OpenTracing 或 OpenTelemetry 的 Nginx 插件,在请求进入时将 $request_id 映射为标准 trace header(如 traceparent 或 uber-trace-id),否则链路会断裂。
实操建议:
- 使用
nginx-opentracing模块(v0.9+)或opentelemetry-nginx-module(推荐新项目),二者均支持从$request_id初始化 trace —— 但需显式配置ot_tracer operation_name和ot_tracer inject_request_id on - 若用
opentelemetry-nginx-module,必须在http块中启用otel_exporter_otlp_endpoint并设置otel_propagators "tracecontext,baggage",否则$request_id不会被注入为traceparent - 避免直接用
proxy_set_header X-Request-ID $request_id替代 tracing header:Jaeger SDK 不读这个字段,下游 Spring Cloud Sleuth 或 otel-go 会忽略它
为什么 $request_id 在跨网关时经常丢失或重复
Nginx 默认只在本机生成一次 $request_id,但若上游是另一层 Nginx 网关且未透传原始 ID,后续网关会生成新 ID,导致 trace 分裂。更隐蔽的问题是:某些负载均衡器(如 ALB、Nginx stream 模块)根本不支持 HTTP header 透传,$request_id 根本到不了应用层。
关键控制点:
- 所有中间 Nginx 层必须统一开启
real_ip_header X-Forwarded-For并配置set_real_ip_from,否则$request_id可能被误判为伪造 - 上游网关必须用
proxy_set_header X-Request-ID $request_id+proxy_set_header traceparent $opentracing_context_traceparent双 header 透传,单传一个不够 - 如果使用 Kubernetes Ingress Controller(如 nginx-ingress),确认其版本 ≥1.9,旧版默认禁用
$request_id生成,需手动加enable-request-id: "true"annotation
$request_id 与 Jaeger trace ID 的格式兼容性问题
$request_id 是 UUID v4(如 f6e522c7-8f9a-4b2e-9c1a-3d4e5f6a7b8c),而 Jaeger 的 uber-trace-id 是 traceid:spanid:parentid:flags 四段十六进制格式(如 4a2e5f6a7b8c9d0e:1a2b3c4d5e6f7890:0000000000000000:01)。二者不能直接等价替换,强行赋值会导致 Jaeger UI 显示 “invalid trace ID”。
安全做法:
- 不要用
map $request_id $jaeger_trace_id { ... }手动转换 —— UUID 转 16 进制 trace ID 无标准算法,下游解析失败率高 - 应让 Nginx tracing 模块接管:它会在收到请求时检查是否存在有效
traceparent,有则复用;无则用$request_id作为 seed 生成合规 trace ID(模块内部调用 libopentracing 的随机生成器) - 验证是否生效:在 upstream 应用日志中 grep
traceparent,确认其格式为00-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx-01,而非原始 UUID
调试链路断裂时,优先检查哪几个 header
链路断开几乎总是 header 透传异常所致,而不是代码逻辑问题。比起翻日志,先抓包看 header 更快。
必须逐跳检查的字段:
-
traceparent:OpenTracing 标准字段,Nginx tracing 模块默认注入,缺失说明模块未生效或配置未加载 -
uber-trace-id:旧版 Jaeger 客户端依赖此字段,若下游是 Java + jaeger-client ≤1.7,必须同时透传该 header -
X-Request-ID:仅作审计用途,不影响 tracing,但可用于比对各跳$request_id是否一致 -
X-B3-TraceId:若链路中有 Zipkin 兼容服务(如某些 Python Flask 微服务),需额外透传,否则该段无法接入 Jaeger
最常被忽略的是:Nginx 的 underscores_in_headers on 必须开启,否则含下划线的 header(如 X-Request-ID)会被直接丢弃,连 access_log 都看不到。


















