异步下单链路查日志时 traceId 一列全是 null,同一个请求在网关有 id,进到线程池里的日志就断了,链路平台拼不出完整调用。乍看像缓存或者权限的锅,追下去往往不是。

Map<String,String> ctx = MDC.getCopyOfContextMap();
executor.submit(() -> {
    MDC.setContextMap(ctx);
    try { handle(); } finally { MDC.clear(); }
});

追下去是这么回事:MDC 底层是 ThreadLocal,值只挂在提交任务的那个线程上。任务换到池里的工作线程执行,取不到原来的 map,日志模板只能输出 null。

碰到「异步上下文丢失」这类问题,我习惯先把当前配置原样备份一份,改坏了立刻换回来,不用现场推。一次只改一处,改完立刻验证,几个改动叠在一起,出问题就说不清是谁导致的。

先做最小复现,能稳定跑出来的问题,排查成本会低一个数量级。别只看报错的最后一行,往上看几行,真正的起因通常在上面。

具体做法是,提交任务前把 MDC 上下文复制出来 包一层再进池;用装饰器包装 Runnable 执行前 set 执行后 clear;或者接 TransmittableThreadLocal 注意版本和 agent 配置;用一次请求串起网关到落库的日志 确认 traceId 一致。

验收就看一点,同一次下单的所有日志 traceId 一致,链路平台上能看到完整节点。

作者 9823189