Cree un andamiaje de desarrollo desde cero para mejorar la función de seguimiento en el escenario del grupo de subprocesos asincrónicos
prefacio
Los siguientes dos artículos son la base y el principio de la función de rastreo escrita anteriormente.
- Cree andamios de desarrollo desde cero y use MDC para implementar el seguimiento de enlaces de registro
- Creación y desarrollo de andamios desde cero para seguimiento de enlaces ligeros Trace
Sin embargo, en el escenario donde hay subprocesos asincrónicos en el negocio, la función de seguimiento es un poco defectuosa, consulte la siguiente descripción para obtener más detalles.
Código de ejemplo de pregunta
// 有个业务线程池
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();
}
Registro de resultados :
// 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
Vemos dos problemas con los registros.
userId
Pregunta 1: La asincronía hace que el subproceso secundario pierda la suma en el subproceso principaltraceId
.- Pregunta 2: La asincronía hace que el subproceso secundario y el subproceso principal no usen un objeto Trace, es decir, la parte 1 y la parte 2 del registro anterior están divididas .
mejorar
Resolver el problema anterior es realmente muy simple, solo manéjelo de forma asincrónica, copie manualmente el valor en el subproceso local del subproceso principal al subproceso secundario y bórrelo después de usarlo .
pseudocódigo
// 父线程信息
userId/traceId/trace = LakerThreadlocal.get();
pool.submit(() -> {
// 传递到子线程
LakerThreadlocal.set(userId/traceId/trace);
// 业务处理
......
// 清空
LakerThreadlocal.clear();
}
El pseudocódigo anterior es el código central para resolver el problema y luego encapsulé esta lógica en EasyAdminMDCThreadPoolExecutor.java .
Los usuarios solo necesitan modificar el grupo de subprocesos anterior, el código de muestra es el siguiente.
ThreadPoolExecutor pool = new EasyAdminMDCThreadPoolExecutor(10,10,"laker");
El efecto de registro en este momento es el siguiente
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 // 这里是被修复处
Dirección del código completo : https://gitee.com/lakernote/easy-admin