性能文章>【全网首发】Skywalking的Trace信息可以跨线程吗>

【全网首发】Skywalking的Trace信息可以跨线程吗原创

2月前
207600

Skywalking的Trace信息可以跨线程吗

Trace信息是一个重要的信息,那么Skywalking的trace可以跨线程传播吗?

我们先给出答案,它是是可以的跨线程传播的,今天就带大家看一下Trace跨线程的使用和实现原理

使用

private static final ExecutorService SERVICE = Executors.newSingleThreadExecutor(r -> {
    Thread thread = new Thread(r);
    thread.setDaemon(true);
    return thread;
});

public void asyncRunnable(Runnable runnable) {
    SERVICE.submit(RunnableWrapper.of(runnable));
}

public void asyncCallable(Callable<Boolean> callable) {
    SERVICE.submit(CallableWrapper.of(callable));
}
public void asyncSupplier(Supplier<Boolean> supplier) {
    CompletableFuture.supplyAsync(SupplierWrapper.of(supplier));
}

定义单个线程池

RunnableWrapper包装Runnable对象实现Trace的跨线程

CallableWrapper包装Callable接口对象来实现Trace的跨线程

SupplierWrapper包装Supplier对象实现Trace的跨线程

这样Skywalking就可以捕捉到线程的trace信息了,那么它是怎么实现的呢?

实现原理

通过看Skywalking的apm-application-toolkit模块,可以看到RunnableWrapper、CallableWrapper类和SupplierWrapper类都有一个特点,那就是类上都有一个注解@TraceCrossThread,这个注解显然是Trace跨线程的意思

谁会扫描@TraceCrossThread注解呢?

apm-toolkit-trace-activation模块下的CallableOrRunnableActivation会对标注@TraceCrossThread注解的的类和call()方法、run()方法或者get()的方法进行拦截增强,对应拦截器为CallableOrRunnableInvokeInterceptor

CallableOrRunnableConstructInterceptor

CallableOrRunnableActivation还定义了构造方法的切入点,对标注@TraceCrossThread注解的类的任何构造方法进行拦截,拦截器为CallableOrRunnableConstructInterceptor,看一下这个拦截器的增强逻辑

CallableOrRunnableConstructInterceptor类:

public class CallableOrRunnableConstructInterceptor implements InstanceConstructorInterceptor {
    @Override
    public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
        if (ContextManager.isActive()) {
            objInst.setSkyWalkingDynamicField(ContextManager.capture());
        }
    }

}

代码比较简答,也就是将当前 TracingContext 的核心信息填充到 ContextSnapshot 中,并添加到_$EnhancedClassField_ws 字段中,接下来实例方法的增强会用到这个信息。

CallableOrRunnableInvokeInterceptor

beforeMethod()方法

CallableOrRunnableInvokeInterceptor的beforeMethod()方法:

public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
    MethodInterceptResult result) throws Throwable {
    ContextManager.createLocalSpan("Thread/" + objInst.getClass().getName() + "/" + method.getName());
    ContextSnapshot cachedObjects = (ContextSnapshot)objInst.getSkyWalkingDynamicField();
    if (cachedObjects != null) {
        ContextManager.continued(cachedObjects);
    }
}
  1. 创建新的TracingContext,创建LocalSpan
  2. 判断ContextSnapshot对象是否为空,如果不为空,调用ContextManager.continued()方法在此段和跨线程段之间建立引用,填充TracingContext信息。

afterMethod()方法

CallableOrRunnableInvokeInterceptor的afterMethod()方法:

@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
    Object ret) throws Throwable {
    ContextManager.stopSpan();
    // clear ContextSnapshot
    objInst.setSkyWalkingDynamicField(null);
    return ret;
}

关闭span,清空ContextSnapshot信息,防止内存泄露的情况。

总结

这篇文章我们介绍了Skywalking的Trace信息是怎么实现跨线程的,核心逻辑是CallableOrRunnableActivation对标注@TraceCrossThread注解的类的构造方法和get()方法、run()方法和call()方法进行拦截增强,构造方法拦截增强的逻辑由CallableOrRunnableConstructInterceptor实现,主要的是向_EnhancedClassField_ws 字段中添加当前Trace的信息,在run()方法等方法执行前拦截器CallableOrRunnableInvokeInterceptor进行拦截,创建新的TracingContext和LocalSpan,判断_EnhancedClassField_ws字段中是否有相关trace信息,如果有就添加到新建的TracingContext中。

❤️ 感谢大家

如果你觉得这篇内容对你挺有有帮助的话:

  1. 欢迎关注我❤️,点赞👍🏻,评论🤤,转发🙏
  2. 关注盼盼小课堂,定期为你推送好文,还有群聊不定期抽奖活动,可以畅所欲言,与大神们一起交流,一起学习。
  3. 有不当之处欢迎批评指正。

💥看到这里的你,如果对于我写的内容很感兴趣,有任何疑问,欢迎在下面留言📥,会第一次时间给大家解答,谢谢!

分类:标签:
请先登录,感受更多精彩内容
快去登录吧,你将获得
  • 浏览更多精彩评论
  • 和开发者讨论交流,共同进步

为你推荐

大数据中台之Kafka,到底好在哪里?
Hello,大家好,今天给大家分享一个大数据里面很火的技术——Kafka,Kafka 是一个分布式的消息系统,其高性能在圈内很出名。本人阅读过多个大数据生态的开源技术的源码,个人感觉 Kafka 的源
什么?搞不定Kafka重复消费?
今天我们聊一个话题,如何保证 Kafka 消息不重复消费?在使用 Kafka 的时候一般都会设置重试的次数,但是因为网络的一些原因,设置了重试就有可能导致有些消息重复发送了(当然导致消息重复也有可能是其他原因),那么怎么解决消息重复这个问题呢?
Kafka的生产者优秀架构设计
前言 Kafka 是一个高吞吐量的分布式的发布订阅消息系统,在全世界都很流行,在大数据项目里面使用尤其频繁。笔者看过多个大数据开源产品的源码,感觉 Kafka 的源码是其中质量比较上乘的一个,这得益于
一次 Docker 容器内大量僵尸进程排查分析
前段时间线上的一个使用 Google Puppeteer 生成图片的服务炸了,每个 docker 容器内都有几千个孤儿僵死进程没有回收,如下图所示。这篇文章比较长,主要就讲了下面这几个问题。- 什么情
What?一个 Dubbo 服务启动要两个小时!
前言前几天在测试环境碰到一个非常奇怪的与 ```dubbo``` 相关的问题,事后我在网上搜索了一圈并没有发现类似的帖子或文章,于是便有了这篇。希望对还未碰到或正在碰到的朋友有所帮助。 现象现象是这样
Prometheus时序数据库-报警的计算
前言在前面的文章中,笔者详细的阐述了Prometheus的数据插入存储查询等过程。但作为一个监控神器,报警计算功能是必不可少的。自然的Prometheus也提供了灵活强大的报警规则可以让我们自由去发挥
【全网首发】APM工具Skywalking是如何进行JVM监控的
Skywalking是如何进行JVM监控的大家都知道Skywalking可以监控Java的JVM情况,包括垃圾回收情况等等,那么它是怎么实现的呢?今天就带大家一探究竟。通过前几篇的文章我们知道,Skywalking启动的时候,会加载各种BootService实现类,而有关JVM的BootServ
【全网首发】Skywalking的Trace信息可以跨线程吗
Skywalking的Trace信息可以跨线程吗Trace信息是一个重要的信息,那么Skywalking的trace可以跨线程传播吗?我们先给出答案,它是是可以的跨线程传播的,今天就带大家看一下Trace跨线程的使用和实现原理使用private static final ExecutorSe
0
0