OpenTelemetry 与 Jaeger 链路追踪
当前方案
项目从旧版 Spring Cloud Sleuth + Zipkin 文档方案迁移到 Spring Boot 4 原生支持的 Micrometer Tracing + OpenTelemetry:
浏览器/客户端
-> joolun-gateway
-> OpenFeign / HTTP
-> Java 业务服务
-> OTLP/HTTP
-> Jaeger v2
- Micrometer Tracing 负责 Spring 应用内的观测与链路抽象。
- OpenTelemetry 负责 Trace 实现和 W3C Trace Context 传播。
- OTLP 是应用上报链路数据的标准协议。
- Jaeger v2 在开发环境中同时提供 OTLP 接收、内存存储和查询界面。
Spring Cloud Sleuth 已停止维护,并且不支持 Spring Boot 3 及以上版本,项目不得重新引入 Sleuth。
Maven 依赖
根 pom.xml 统一引入以下依赖,所有 Java 服务继承:
<!-- OpenTelemetry 分布式链路追踪,通过 OTLP 上报到 Jaeger 或 Collector -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-opentelemetry</artifactId>
</dependency>
<!-- 为 OpenFeign 调用创建 Observation 并传播 W3C Trace Context -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-micrometer</artifactId>
</dependency>
Spring Boot / Spring Cloud BOM 统一管理版本,不要为这两个依赖单独指定版本。
服务配置
本项目已覆盖 10 个 Java 服务:joolun-auth、joolun-codegen、joolun-gateway、joolun-live-admin、joolun-mall-admin、joolun-mall-api、joolun-monitor、joolun-pay-admin、joolun-upms-admin、joolun-weixin-admin。既有 Compose 中的 9 个 Java 服务已配置 Trace 导出;未列入 Compose 的服务通过启动环境变量显式开启,无需为同步链路追踪额外新增业务容器。
各 Java 服务的 application.yml 使用相同配置:
management:
# 默认不向外部上报指标;与下方 Trace 导出开关相互独立。
otlp:
metrics:
export:
enabled: false
tracing:
export:
otlp:
enabled: ${JOOLUN_TRACING_EXPORT_ENABLED:false}
sampling:
probability: ${JOOLUN_TRACING_SAMPLING_PROBABILITY:0.1}
opentelemetry:
tracing:
export:
otlp:
endpoint: ${OTEL_EXPORTER_OTLP_TRACES_ENDPOINT:http://127.0.0.1:4318/v1/traces}
环境变量说明:
| 环境变量 | 默认值 | 说明 |
|---|---|---|
JOOLUN_TRACING_EXPORT_ENABLED |
false |
是否启用 OTLP Trace 导出,不控制指标导出;应用内 Trace 与上下文传播仍可继续工作 |
JOOLUN_TRACING_SAMPLING_PROBABILITY |
0.1 |
根链路采样比例,范围为 0.0 到 1.0 |
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT |
http://127.0.0.1:4318/v1/traces |
OTLP/HTTP Trace 接收地址 |
spring.application.name 会作为 OpenTelemetry 的 service.name,不需要为每个服务重复配置。
为了不影响尚未部署链路后端的现有环境,OTLP Trace 导出默认关闭。开发环境 Docker Compose 会显式开启 Trace 导出并将采样率覆盖为 1.0,但 OTLP 指标导出仍然关闭;生产环境不要长期使用全量采样,应根据流量和存储容量调整。
OTLP 指标默认关闭
spring-boot-starter-opentelemetry 除了 Trace 组件,还会引入 micrometer-registry-otlp。如果不显式关闭指标导出,指标注册器可能周期性尝试向默认的 http://localhost:4318/v1/metrics 上报数据;没有接收端时会出现以下日志:
OtlpHttpMetricsSender.send
OtlpMeterRegistry.publish
java.net.ConnectException: Connection refused
因此,本项目全部 10 个 Java 服务在本地 application.yml 中统一设置 management.otlp.metrics.export.enabled: false。这只关闭 OTLP 指标向外部推送,不关闭 Micrometer 本地指标采集,也不关闭 Trace 或日志中的 Trace ID;Actuator 指标端点仍受其原有暴露与访问配置控制。
两个开关必须分别理解:
| 配置项 | 控制内容 | 项目默认值 |
|---|---|---|
management.otlp.metrics.export.enabled |
Metrics 指标导出 | false |
management.tracing.export.otlp.enabled |
Trace 链路导出 | ${JOOLUN_TRACING_EXPORT_ENABLED:false} |
仅设置 JOOLUN_TRACING_EXPORT_ENABLED=false 不能关闭 Metrics。当前部署的 Jaeger 用于接收 Trace,不能把 /v1/traces 配置成指标地址,也不能仅启动 Jaeger 就认为已接入指标后端。
将来需要导出指标时,先部署启用了 Metrics 接收与导出管线的 OpenTelemetry Collector 或兼容指标后端,再通过 Nacos 环境配置或启动环境变量显式覆盖:
MANAGEMENT_OTLP_METRICS_EXPORT_ENABLED=true
MANAGEMENT_OTLP_METRICS_EXPORT_URL=http://<指标接收端主机>:4318/v1/metrics
更新本地配置后,需要重新构建并重启相关服务。若升级后仍出现上述日志,检查 Nacos、环境变量和启动参数是否覆盖了 management.otlp.metrics.export.enabled;也应确认运行的是新配置对应的构建产物。本文不要求修改现有线上 Nacos 配置,默认值随应用发布生效。
本地默认值与 Nacos 配置分层
各服务的本地 application.yml 保留安全默认值:Metrics 导出关闭、Trace 导出默认关闭。Nacos 公共 application-dev.yml 可统一覆盖当前环境的导出开关、采样率和接收地址,服务私有配置仅用于例外;不要把这些配置放到 spring 下,它们统一属于顶层 management。本次同步不修改线上 Nacos,也不承诺修改导出器配置后无需重启。
启动 Jaeger
以下命令均在后端仓库根目录执行(Compose 路径为 docker-files/docker-compose.yml)。
仅启动 Jaeger:
docker compose -f docker-files/docker-compose.yml up -d joolun-plus-jaeger
启动整套开发环境:
docker compose -f docker-files/docker-compose.yml up -d
端口用途:
| 端口 | 用途 |
|---|---|
16686 |
Jaeger 查询界面,访问 http://127.0.0.1:16686 |
4317 |
OTLP/gRPC 接收端口 |
4318 |
OTLP/HTTP 接收端口,Java 服务当前使用此端口 |
同一台主机并行运行多套项目时,注意 Jaeger 的宿主机端口 16686、4317、4318 和容器名不能冲突;可复用一个接收端,或通过独立的 Compose 覆盖文件调整映射,并同步修改非容器服务的接收地址与查询界面地址。
开发环境的 Jaeger v2 all-in-one 使用内存存储,容器重启后链路数据会丢失,不得直接作为生产部署方案。
日志关联
自定义 logback-spring.xml 的控制台、普通文件和错误文件格式都包含:
[traceId=...,spanId=...]
一次请求经过多个 Java 服务时,可以复制 Jaeger 中的 Trace ID 到日志系统中检索,或从日志中的 Trace ID 回查 Jaeger。
没有活动 Trace 的启动日志、定时日志中,这两个字段可能为空,这是正常现象。
验证链路
- 启动 Jaeger、Nacos、Gateway 和至少一个业务服务。
- 非 Docker Compose 启动时设置
JOOLUN_TRACING_EXPORT_ENABLED=true和JOOLUN_TRACING_SAMPLING_PROBABILITY=1.0,开启上报并避免抽样导致测试请求不可见。 - 通过 Gateway 调用一个会继续触发 OpenFeign 请求的接口。
- 打开
http://127.0.0.1:16686,选择joolun-gateway或对应业务服务并查询。 - 确认同一 Trace 中存在 Gateway 和下游服务 Span,且两端日志使用相同 Trace ID。
自动传播依赖 Spring 提供或自动配置的客户端。手工 new RestTemplate()、new RestClient() 或 new WebClient() 不会自动注入链路上下文,应使用自动配置的 RestTemplateBuilder、RestClient.Builder 或 WebClient.Builder。
当前覆盖边界
第一阶段覆盖:
- Spring MVC 和 Spring WebFlux 入站请求。
- Spring Cloud Gateway 转发。
- OpenFeign 服务间 HTTP 调用。
- Java 服务日志中的 Trace ID 和 Span ID。
当前尚未保证完整传播:
- RocketMQ 消息生产与消费。
- Redis Pub/Sub、WebSocket 后台事件。
@Async、自定义线程池及定时任务产生的新执行链路。server/Open-IM-Server下的 Go 服务。
这些场景需要分别注入和提取 W3C traceparent,完成前不能把异步消息或 Open-IM 调用视为完整端到端链路。
生产部署建议
生产环境建议在应用与后端之间增加 OpenTelemetry Collector:
Java/Go 服务
-> OpenTelemetry Collector
-> Jaeger、Tempo、Elastic 或其他 OTLP 后端
Collector 统一负责批处理、重试、限流、敏感属性过滤和后端切换。生产部署还必须配置持久化存储、TLS、访问认证、数据保留周期和采样策略;不得使用当前 Compose 中的 Jaeger 内存存储。
官方资料: