公司排查一个异步任务异常,在 ELK 里搜对应的 requestId,搜出来的日志只有主线程的。异步线程里的日志一条都没搜到——因为 MDC 里的 requestId 根本没有传到异步线程里。异步线程打出来的日志,requestId 是空的。一整条调用链在异步这个节点断掉了。 问题很直接:@Async 用一个线程池执行任务,但 MDC 是基于 ThreadLocal 的,ThreadLocal 不会自动从主线程传到子线程。异步线程里 MDC.get("requestId") 返回 null,日志里就少了这条 key。 今天聊聊怎么用 TransmittableThreadLocal(TTL)把主线程的上下文透传到异步线程里。 为什么 ThreadLocal 不行,TTL 就行 ThreadLocal 的一个基本特性:子线程拿不到父线程的值。 主线程里 MDC.put("requestId", "abc123"),然后 @Async 开一个新线程去执行,新线程里 MDC.get("requestId") 是 null。 一个直觉的解法是调用线程池时手动传参数。把 requestId ....
