从零搭建开发脚手架 异步线程池场景下增强Trace功能
前言
下面两篇文章是之前写的trace功能的基础和原理。
但是在业务中有异步线程场景下,trace功能有点儿瑕疵,具体看下面的描述。
问题示例代码
// 有个业务线程池
ThreadPoolExecutor pool = new EasyAdminThreadPoolExecutor(10,10,"laker");
// 模拟业务代码
public void pageList(){
// 1.本地查询
xxxService.pageList();
// 2.模拟异步远程调用,耗时300ms
pool.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 // 这里是被修复处