调用链追踪(Trace ID)

前言:

在 Java 中实现 调用链追踪(Trace ID) 通常用于分布式系统中跟踪请求的完整链路,常见的实现方式包括手动编码或使用开源框架(如 SkyWalkingZipkinSpring Cloud Sleuth 等)。以下是具体实现方法及示例:

1. 手动实现 Trace ID

通过 ThreadLocal 或 MDC(Mapped Diagnostic Context)存储 Trace ID,并在请求链路中传递。

步骤 1:定义 Trace ID 工具类
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 ID
    public 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:

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 {
    @Override
    public 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
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 丢失问题:

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 SleuthSpring Cloud 微服务项目自动化集成,支持 Zipkin 可视化依赖 Spring 生态
SkyWalking企业级监控,多语言支持功能强大,支持全链路追踪需部署额外服务

根据项目需求选择合适方案!

学海无涯,志当存远。燃心砺志,奋进不辍。愿诸君得此鸡汤,如沐春风,学业有成。若觉此言甚善,烦请赐赞一枚,共励学途,同铸辉煌

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值