前言:
在 Java 中实现 调用链追踪(Trace ID) 通常用于分布式系统中跟踪请求的完整链路,常见的实现方式包括手动编码或使用开源框架(如 SkyWalking
、Zipkin
、Spring Cloud Sleuth
等)。以下是具体实现方法及示例:
1. 手动实现 Trace ID
通过 ThreadLocal
或 MDC
(Mapped Diagnostic Context)存储 Trace ID,并在请求链路中传递。
步骤 1:定义 Trace ID 工具类
java">import org.slf4j.MDC;
import java.util.UUID;public class TraceIdUtil {private static final String TRACE_ID_KEY = "traceId";private static final ThreadLocal<String> traceIdHolder = new ThreadLocal<>();// 生成或获取当前 Trace IDpublic static String getOrGenerateTraceId() {String traceId = MDC.get(TRACE_ID_KEY);if (traceId == null) {traceId = UUID.randomUUID().toString().replace("-", "");MDC.put(TRACE_ID_KEY, traceId);traceIdHolder.set(traceId);}return traceId;}// 清除 Trace ID(防止内存泄漏)public static void clear() {MDC.remove(TRACE_ID_KEY);traceIdHolder.remove();}
}
步骤 2:在 HTTP 请求中传递 Trace ID
通过拦截器在请求头中添加 Trace ID:
java">import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import java.io.IOException;public class TraceIdInterceptor implements ClientHttpRequestInterceptor {@Overridepublic ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {String traceId = TraceIdUtil.getOrGenerateTraceId();request.getHeaders().add("X-Trace-Id", traceId);return execution.execute(request, body);}
}
步骤 3:在日志中输出 Trace ID
配置 logback.xml
,在日志模板中添加 %X{traceId}
:
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] [%X{traceId}] %-5level %logger{36} - %msg%n</pattern>
2. 使用 Spring Cloud Sleuth + Zipkin(推荐)
Spring Cloud Sleuth 自动集成 Trace ID,Zipkin 提供可视化追踪。
步骤 1:添加依赖
<!-- Spring Cloud Sleuth -->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency><!-- Zipkin 上报 -->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
步骤 2:配置 application.yml
java">spring:sleuth:sampler:probability: 1.0 # 采样率(1.0=100%上报)zipkin:base-url: http://localhost:9411 # Zipkin 服务地址
步骤 3:查看调用链
启动 Zipkin 服务后,访问 http://localhost:9411
查看完整的调用链路。
3. 使用 SkyWalking
SkyWalking 是一款开源的 APM 系统,支持自动链路追踪。
步骤 1:下载并启动 SkyWalking
# 下载 SkyWalking
wget https://archive.apache.org/dist/skywalking/9.6.0/apache-skywalking-apm-9.6.0.tar.gz
tar -zxvf apache-skywalking-apm-9.6.0.tar.gz
cd apache-skywalking-apm-bin# 启动 SkyWalking
bin/startup.sh
步骤 2:Java 应用接入 Agent
在 JVM 启动参数中添加 Agent:
-javaagent:/path/to/skywalking-agent/skywalking-agent.jar
-Dskywalking.agent.service_name=your-service-name
-Dskywalking.collector.backend_service=localhost:11800
4. 异步线程传递 Trace ID
使用 TransmittableThreadLocal
解决线程池中 Trace ID 丢失问题:
java">import com.alibaba.ttl.TransmittableThreadLocal;public class TraceContext {private static final TransmittableThreadLocal<String> traceIdHolder = new TransmittableThreadLocal<>();public static void setTraceId(String traceId) {traceIdHolder.set(traceId);}public static String getTraceId() {return traceIdHolder.get();}public static void clear() {traceIdHolder.remove();}
}// 在线程池任务中调用
ExecutorService executor = TtlExecutors.getTtlExecutorService(Executors.newFixedThreadPool(10));
executor.submit(() -> {System.out.println("Trace ID: " + TraceContext.getTraceId());
});
关键点总结
方案 | 适用场景 | 优点 | 缺点 |
---|---|---|---|
手动实现 Trace ID | 简单项目或框架不支持链路追踪时 | 轻量级,无依赖 | 需自行处理传递逻辑 |
Spring Cloud Sleuth | Spring Cloud 微服务项目 | 自动化集成,支持 Zipkin 可视化 | 依赖 Spring 生态 |
SkyWalking | 企业级监控,多语言支持 | 功能强大,支持全链路追踪 | 需部署额外服务 |
根据项目需求选择合适方案!