从零搭建开发脚手架 异步线程池场景下增强Trace功能
从零搭建开发脚手架 异步线程池场景下增强Trace功能
前言
下面两篇文章是之前写的trace功能的基础和原理。
- 从零搭建开发脚手架 使用MDC实现日志链路跟踪
- 从零搭建开发脚手架 轻量级链路追踪Trace
但是在业务中有异步线程场景下,trace功能有点儿瑕疵,具体看下面的描述。
问题示例代码
// 有个业务线程池
ThreadPoolExecutor pool = new EasyAdminThreadPoolExecutor(10,10,"laker");
// 模拟业务代码
public void pageList(){// 1.本地查询xxxService.pageList();// 2.模拟异步远程调用,耗时300mspool.submit(() -> {TraceCodeBlock.trace("remoteService.call", value -> {TimeUnit.MILLISECONDS.sleep(300);}); }// 3.本地插入记录xxxService.insert();
}
结果日志:
// 1 线程laker-9 丢掉了userId和traceId
20:21:35.534 INFO --- [ laker-9] [|] com.laker.admin.framework.aop.trace.Trace:86 `---`---[302ms] Others-remoteService.call
// 2 tomcat线程 userId=16还有traceId
20:21:35.547 INFO --- [io-8080-exec-38] [16|497ef9d28d20452f84443c66c6f25354] com.laker.admin.framework.aop.trace.Trace:86 `---`---[428ms] Controller-ExtLeaveController|pageAll+---[max]:[414ms] Controller-ExtLeaveController.pageAll| +---[32ms] Others-leaveService.page| | +---[3ms] Mapper-com.laker.admin.module.ext.mapper.ExtLeaveMapper.selectPage_mpCount| | `---[1ms] Mapper-com.laker.admin.module.ext.mapper.ExtLeaveMapper.selectPage
我们看到日志有两个问题。
- 问题1:异步导致子线程丢掉了父线程中的
userId
和traceId
。 - 问题2:异步导致子线程和父线程使用的不是一个Trace对象,即上面日志中1部分和2部分割裂现象。
增强
解决上面的问题其实很简单,只需在异步时处理下,把父线程的threadlocal中的值手动复制到子线程中去,并且在使用完毕后清除即可。
伪代码
// 父线程信息
userId/traceId/trace = LakerThreadlocal.get();
pool.submit(() -> {// 传递到子线程LakerThreadlocal.set(userId/traceId/trace);// 业务处理......// 清空LakerThreadlocal.clear();
}
上面的伪代码就是解决问题的核心代码了,然后我封装了下把这个逻辑封装到EasyAdminMDCThreadPoolExecutor.java中。
使用者只需要把之前的线程池修改下即可,示例代码如下。
ThreadPoolExecutor pool = new EasyAdminMDCThreadPoolExecutor(10,10,"laker");
这个时候的日志效果如下
20:21:35.547 INFO --- [io-8080-exec-38] [16|497ef9d28d20452f84443c66c6f25354] com.laker.admin.framework.aop.trace.Trace:86 `---`---[428ms] Controller-ExtLeaveController|pageAll+---[max]:[414ms] Controller-ExtLeaveController.pageAll| +---[410ms] Others-leaveService.page| | +---[3ms] Mapper-com.laker.admin.module.ext.mapper.ExtLeaveMapper.selectPage_mpCount| | `---[1ms] Mapper-com.laker.admin.module.ext.mapper.ExtLeaveMapper.selectPage| | +---[302ms] Others-remoteService.call // 这里是被修复处
完整代码地址:https://gitee.com/lakernote/easy-admin