SkyWalking8.x监控异步跨线程问题
- 一. 异步多线程问题
- 添加依赖
- 开启异步多线程
- 测试类方法
- Controller层处理
- 分析
- 二. 指定跟踪上下文的K-V
- 制作不易,求一个点赞+关注~~
一. 异步多线程问题
首先,Skywalking是一款基于java代理的监控系统,但是在监控多线程跨线程的时候却会意外失联,这就让我们没办法去追踪调用链路问题
类似于下图
@GetMapping("/task1")
public CommonReturnType task1() throws Exception {
for (int i = 0; i < 5; i++) {
new Thread(()->{
log.info("1");
});
}
return CommonReturnType.creat(1);
}
当然,只是为了演示简单,就没有写异步多线程,SkyWalking默认情况下只会采集同一线程的调用链路,如果应用里面采用了多线程,同时希望追踪链路能将多个线程的链路关联起来。则需要使用插件apm-toolkit-trace,下面通过一个小Demo来进行演示
添加依赖
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-trace</artifactId>
<version>8.4.0</version>
</dependency>
开启异步多线程
主动启动类添加
@SpringBootApplication
@EnableAsync
public class IotMain8239 {
public static void main( String[] args )
{
SpringApplication.run(IotMain8239.class,args);
}
}
测试类方法
import com.fehead.Iot.mapper.GwKkkTest1Mapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.skywalking.apm.toolkit.trace.ActiveSpan;
import org.apache.skywalking.apm.toolkit.trace.RunnableWrapper;
import org.apache.skywalking.apm.toolkit.trace.TraceContext;
import org.apache.skywalking.apm.toolkit.trace.TraceCrossThread;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Component
@Slf4j
public class HelloTask {
@Autowired
GwKkkTest1Mapper gwKkkTest1Mapper;
ExecutorService executorService = Executors.newCachedThreadPool();
@Async
public void asynchelloWorld(){
try {
Thread.sleep(5000);
//插入数据库用户
GwKkkTest1 gwKkkTest1 = new GwKkkTest1(40000, "s", "s", "s");
executorService.submit(RunnableWrapper.of(()->{
gwKkkTest1Mapper.insert(gwKkkTest1);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Optional<String> value = TraceContext.getCorrelation("key"); //拿到同一链路的指定key
log.info("down : insert1 + " +value.get());
}) );
executorService.submit(RunnableWrapper.of(()->{
gwKkkTest1Mapper.insert(gwKkkTest1);
try {
Thread.sleep(7000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Optional<String> value = TraceContext.getCorrelation("jia"); //拿到同一链路的指定key
log.info("down : insert2 + " +value.get());
}) );
log.info("down : HelloTask");
// ActiveSpan.tag("intask", "王凯艺"); 打标记k,v
}catch (Exception e){
e.printStackTrace();
}
}
}
Controller层处理
@Autowired
HelloTask helloTask;
@GetMapping("/task")
public CommonReturnType task() throws Exception {
ActiveSpan.tag("type", "异步任务多线程任务");
log.info("come in : /task");
TraceContext.putCorrelation("key", "kaikai");
TraceContext.putCorrelation("jia", "jiajia");
helloTask.asynchelloWorld();
return CommonReturnType.creat(1);
}
- 我们可以通过 ActiveSpan.tag(“type”, “异步任务多线程任务”) 去追踪里面添加相应的标签指定K-V
- 在跟踪方法的上下文中添加自定义标签ActiveSpan.tag(“key”, “val”)。
- ActiveSpan.error() 将当前范围标记为错误状态。
- ActiveSpan.error(String errorMsg) 通过消息将当前范围标记为错误状态。
- ActiveSpan.error(Throwable throwable) 使用Throwable将当前范围标记为错误状态。
- ActiveSpan.debug(String debugMsg) 在当前范围中添加调试级别日志消息。
- ActiveSpan.info(String infoMsg) 在当前范围内添加信息级别日志消息。
- ActiveSpan.setOperationName(String operationName) 自定义操作名称。
- 再来查看控制台发现已经打印出异步多线程的路线了,并且追踪ID相同
分析
主要添加RunnableWrapper.of()来指定跟踪线程
executorService.submit(RunnableWrapper.of(()->{
gwKkkTest1Mapper.insert(gwKkkTest1);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Optional<String> value = TraceContext.getCorrelation("key"); //拿到同一链路的指定key
log.info("down : insert1 + " +value.get());
}) );
也可以添加其他多线程方法
CallableWrapper.of()
CompletableFuture.supplyAsync(() ->{});
也可以添加指定实现多线程的类上注解 @TraceCrossThread
@TraceCrossThread
public static class MyTask<String> implements Callable<String> {}
二. 指定跟踪上下文的K-V
类似于ThreadLocal
使用TraceContext.putCorrelation()API将自定义数据放在跟踪上下文中。
Optional<String> previous = TraceContext.putCorrelation("customKey", "customValue");
当值是null或为空时,CorrelationContext将删除该项目。
Optional<String> value = TraceContext.getCorrelation("customKey");
使用TraceContext.getCorrelation()API获取自定义数据。