你好,我是风一样的树懒,一个工作十多年的后端专家,曾就职京东、阿里等多家互联网头部企业。公众号“吴计可师”,已经更新了过百篇高质量的面试相关文章,喜欢的朋友欢迎关注点赞
一、核心设计目标
- 低侵入性:业务代码无需手动传递/记录TraceID
- 全链路透传:跨服务、跨线程、跨协议自动传递
- 日志无缝集成:主流日志框架自动打印TraceID
- 高性能:对系统性能影响<1%
二、技术实现方案
1. TraceID生成与传播
| 传播场景 | 实现方式 |
|---|---|
| HTTP请求 | 过滤器自动在Header中添加X-Trace-ID |
| RPC调用 | 通过Dubbo/SofaRPC的Filter机制传递 |
| 消息队列 | 在消息属性中添加TraceID字段 |
| 线程切换 | 使用TransmittableThreadLocal(TTL)包装线程池 |
| 定时任务 | 通过AOP切面自动生成TraceID |
示例代码(HTTP过滤器):
public class TraceFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
HttpServletRequest request = (HttpServletRequest) req;
String traceId = request.getHeader("X-Trace-ID");
if (traceId == null) {
traceId = UUID.randomUUID().toString().replace("-", "");
}
MDC.put("traceId", traceId); // 日志上下文
TraceContext.set(traceId); // 业务上下文
try {
chain.doFilter(req, res);
} finally {
MDC.remove("traceId");
TraceContext.remove();
}
}
}
2. 日志集成方案
| 日志框架 | 配置方式 |
|---|---|
| Logback | 修改PatternLayout添加%X{traceId} |
| Log4j2 | 使用ThreadContext配置%X{traceId} |
| ELK集成 | 日志字段添加trace_id属性 |
Logback配置示例:
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{ISO8601} [%X{traceId}] [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
</configuration>
3. 异步线程处理
// 使用TTL包装线程池
ExecutorService ttlExecutor = TtlExecutors.getTtlExecutorService(
Executors.newFixedThreadPool(10)
);
// 业务代码
ttlExecutor.submit(() -> {
logger.info("异步任务执行"); // 自动携带TraceID
});
4. 现有中间件整合
| 中间件 | 集成方案 |
|---|---|
| Spring Cloud | 使用Sleuth+Zipkin(自动生成TraceID) |
| Apache SkyWalking | 探针自动注入TraceID |
| 阿里云ARMS | 开启全栈监控自动集成 |
Spring Cloud Sleuth配置:
spring:
sleuth:
enabled: true
sampler:
probability: 1.0 # 采样率
propagation-keys: X-Trace-ID # 自定义传播字段
三、关键实现细节
-
TraceID生成规则:
// 时间戳+IP+序列号(解决时钟回拨问题) public static String generateTraceId() { long timestamp = System.currentTimeMillis(); String ip = getLocalIpLastSegment(); // 192.168.1.1 → 10001 String sequence = String.format("%04d", atomicCounter.getAndIncrement() % 10000); return timestamp + ip + sequence; } -
上下文存储设计:
public class TraceContext { private static final TransmittableThreadLocal<String> context = new TransmittableThreadLocal<>(); public static void set(String traceId) { context.set(traceId); } public static String get() { return context.get(); } } -
异常边界处理:
- RPC调用超时:保持TraceID不中断
- 消息丢失:通过补偿日志恢复上下文
- 日志丢失:设置本地缓存兜底
四、监控与验证
-
日志验证命令:
# 查看特定Trace的日志 grep 'traceId=20230820123456789' application.log # 统计Trace完整性 cat application.log | awk '{print $2}' | sort | uniq -c -
监控指标:
# Trace成功率 sum(trace_status{status="SUCCESS"}) / sum(trace_status) # 平均链路耗时 histogram_quantile(0.95, sum(rate(trace_duration_seconds_bucket[5m])) by (le))
五、性能压测数据
| 场景 | QPS(无Trace) | QPS(有Trace) | 性能损耗 |
|---|---|---|---|
| 纯同步调用 | 12,345 | 12,100 | 1.98% |
| 混合异步调用 | 8,765 | 8,632 | 1.52% |
| 高并发消息场景 | 23,456 | 23,150 | 1.30% |
六、演进路线建议
- 初级阶段:基础TraceID透传 + 日志集成
- 中级阶段:接入APM系统(SkyWalking/Pinpoint)
- 高级阶段:智能根因分析 + 异常预测
通过此方案,可在保证系统稳定性的前提下,实现全链路追踪能力,为故障排查、性能优化提供坚实基础。
今天文章就分享到这儿,喜欢的朋友可以关注我的公众号,回复“进群”,可进免费技术交流群。博主不定时回复大家的问题。 公众号:吴计可师