分布式系统中需通过x-request-id实现日志链路追踪,java应用须结合filter/mdc/线程上下文继承/标准化协议:入口生成并存入mdc,logback配置引用;异步场景需手动复制mdc;跨服务调用须在http头或rpc隐式参数中透传;建议网关统一分配并校验id。

在分布式系统中,为每个请求生成并传递唯一请求ID(如 X-Request-ID),是实现日志链路追踪的关键。Java 应用本身不自动提供跨服务、跨线程的日志上下文透传能力,需结合拦截器、MDC、线程上下文继承和标准化协议协同实现。
使用 MDC 绑定请求 ID 到当前线程日志上下文
MDC(Mapped Diagnostic Context)是 Logback / Log4j2 提供的线程局部日志上下文机制,适合在单次请求生命周期内注入标识信息。
- 在 Web 入口(如 Spring MVC 的
HandlerInterceptor或 Filter)中生成或提取请求 ID,并存入 MDC:
public class RequestIdFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
HttpServletRequest request = (HttpServletRequest) req;
String requestId = Optional.ofNullable(request.getHeader("X-Request-ID"))
.orElse(UUID.randomUUID().toString());
MDC.put("requestId", requestId);
try {
chain.doFilter(req, res);
} finally {
MDC.clear(); // 必须清理,避免线程复用污染
}
}
}- 配置 logback.xml,在 pattern 中引用
%X{requestId}:
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - [req=%X{requestId}] %msg%n</pattern>确保异步/线程池场景下 MDC 正确传递
默认线程池(如 ThreadPoolExecutor)不会自动复制父线程的 MDC,需显式桥接。
- 使用
org.slf4j:MDCInsertingServletFilter(仅限 Servlet 环境)或自定义包装类 - 对
CompletableFuture,用copyMdc()+thenApplyAsync手动传递:
private Map<string string> copyMdc() {
return MDC.getCopyOfContextMap() != null ?
new HashMap(MDC.getCopyOfContextMap()) : Collections.emptyMap();
}
<p>// 使用示例
Map<string string> mdcContext = copyMdc();
CompletableFuture.supplyAsync(() -> {
MDC.setContextMap(mdcContext);
try {
return doSomething();
} finally {
MDC.clear();
}
});</string></p></string>- Spring Boot 可集成
logbook-spring-boot-starter或自定义TaskDecorator实现线程池级 MDC 自动继承
跨服务调用时透传请求 ID
HTTP 调用需在出站请求头中携带 X-Request-ID;RPC(如 Dubbo、gRPC)需通过隐式参数或拦截器注入。
- Spring RestTemplate / WebClient:添加拦截器自动写入 header
- OpenFeign:通过
RequestInterceptor注入:
@Bean
public RequestInterceptor requestInterceptor() {
return template -> template.header("X-Request-ID", MDC.get("requestId"));
}- Dubbo:使用
Filter在 consumer 端 put attachment,在 provider 端从 attachment 取出并写入 MDC - gRPC:通过
ClientInterceptor和ServerInterceptor读写Metadata
统一生成与校验策略提升可靠性
避免不同模块各自生成 ID 导致冲突或缺失,建议集中管控:
- 定义标准工具类(如
RequestIdUtils),封装生成、解析、校验逻辑(支持 traceId/spanId 格式) - 在网关层(如 Spring Cloud Gateway、Nginx)统一分配并注入
X-Request-ID,后端服务只做继承与透传 - 对缺失 ID 的请求可拒绝或打标告警(如日志中输出
[req=MISSING]),便于监控异常链路
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











