技术博客

阅读约 4 分钟

排障总卡在 Nginx?给它也装上 OpenTelemetry

0 · 入口这一跳,经常是盲区

页面慢、接口超时,后端日志翻完还是找不到原因——问题多半卡在最前面那台 Nginx:转发成功没有、花了多久,日志里一概没有。

  • 看不清:入口耗时、转发成败,传统日志对不上
  • 串不上:Nginx 和后端各记各的,拼不成一条链路
  • 不敢动:存量 Nginx,怕加模块影响现网
  • 不想改码:业务侧希望零侵入,最好挂上就能报

做法很简单:Nginx 装 OTel 模块,Java 挂官方探针,都报到 DataBuff —— 一次请求就能看到 Nginx → Java → Redis 完整瀑布。

DataBuff 是开源的 AI Native OpenTelemetry APM:指标、链路、日志和 AI 排障放在一起,原生收 OTLP,Nginx / Java 报上来就能拼成一条 Trace。
GitHub:https://github.com/databufflabs/databuff

1 · 先看效果:一条请求,三层都在

整体就这样:各记各的 Span,带同一个 TraceID 上报,平台拼成瀑布。业务代码一行不用改。

链路示意:Nginx → Java → Redis,双协议上报 DataBuff
图 1 · 链路示意
DataBuff 全局拓扑:nginx → java → redis
图 2 · 全局拓扑:nginx → java → redis
瀑布图:nginx → java → redis,同一 TraceID
图 3 · 瀑布:/hello(nginx)→ GET /hello(java)→ AUTH/SET/GET(redis),同 TraceID,约 975ms
服务列表:nginx 与 java 两个服务
图 4 · 服务列表:两个服务同时被观测
链路追踪页按服务筛选
图 5 · 按服务勾选,只看相关 Trace
2 · 怎么做:两种接入,跟着跑一遍

先准备好能收 OTLP 的 DataBuff(4317 gRPC / 4318 HTTP)。下面命令在装 Nginx、Java 的机器上执行;DataBuff 可以是同机或内网另一台。

方式场景怎么做
方式一全新 / 容器nginx:1.27-alpine-otel,模块内置,docker 挂配置启动
方式二存量 Nginxnginx-module-otel → 写 conf → nginx -tnginx -s reload

两条路的 OTel 指令一样。模块要求 Nginx 1.21+;更旧就走方式一,和宿主机旧 Nginx 互不影响。

共用:完整 nginx.conf(存成文件,地址换成你的 DataBuff / Java;同机可写 127.0.0.1):

load_module /usr/lib/nginx/modules/ngx_otel_module.so;

worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    # 上报到 DataBuff:填 DataBuff 所在机器的 IP,走 gRPC 4317 口
    otel_exporter {
        endpoint <DataBuff机器IP>:4317;
        interval 5s;
    }
    otel_service_name nginx-otel-demo;
    # 关键一行:把 traceparent 透传给后端,否则链路会断
    otel_trace_context propagate;

    server {
        listen 80;
        otel_trace on;

        location / {
            # 反代到 Java 服务
            proxy_pass http://<Java服务IP>:18091;
        }
    }
}

方式一 · 官方 OTel 镜像

镜像里已有模块,挂上刚写的 conf 启动即可:

docker run -d --name nginx-otel \
  -p 8090:80 \
  -v /path/to/nginx.conf:/etc/nginx/nginx.conf:ro \
  nginx:1.27-alpine-otel

改配置后:

docker cp /path/to/nginx.conf nginx-otel:/etc/nginx/nginx.conf
docker exec nginx-otel nginx -t
docker exec nginx-otel nginx -s reload

方式二 · 存量 Nginx 加装模块

先看版本(要 1.21+):

nginx -v

按系统装官方模块(装完可用 ls /usr/lib/nginx/modules/ngx_otel_module.so 确认):

# Alpine
apk add --repository https://nginx.org/packages/mainline/alpine/v3.21/main nginx-module-otel

# CentOS / RHEL(先配 nginx.org 官方 yum 源)
yum install nginx-module-otel

# Debian / Ubuntu(先配 nginx.org 官方 apt 源)
apt install nginx-module-otel

把上面那份完整 conf 写到 /etc/nginx/nginx.conf(或在原 conf 顶部加 load_module,http 块加 otel_*,server 块加 otel_trace on)。然后先测配置、再热加载(不中断现有请求):

nginx -t          # 先测配置对不对
nginx -s reload   # 热加载,不用重启进程

Java 侧 · 挂探针

下载官方 opentelemetry-javaagent.jar,启动时加 JVM 参数。业务代码不用改。Java 走 HTTP 4318,Nginx 走 gRPC 4317,进同一个 DataBuff:

java -javaagent:opentelemetry-javaagent.jar \
  -Dotel.service.name=java-redis-demo \
  -Dotel.exporter.otlp.endpoint=http://<DataBuff机器IP>:4318 \
  -jar your-app.jar

打流量,看瀑布

curl http://你的机器IP:8090/hello

打几次,等约 30 秒(批量导出有延迟),打开 DataBuff「链路追踪」,勾选 nginx-otel-demo,点开任意一条看完整瀑布。

最容易踩的坑:漏写 otel_trace_context propagate;。模块默认不往下游传 TraceID,Nginx 和 Java 会变成两条互不相干的 Trace。加上立刻串成一条。改完记得再 nginx -t && nginx -s reload(容器则 docker exec … nginx -s reload)。

3 · 你可能想问
  • 版本太旧? 走方式一官方镜像,和宿主机旧 Nginx 互不影响。
  • 要改 Java 代码吗? 不用。挂官方 javaagent,HttpServer / Jedis 自动插桩。
  • 加模块影响现网? nginx -t 通过后 nginx -s reload 热加载即可。
  • 建议路径 测试环境先方式一跑通,存量再方式二加装。