/chy-skywalking-plugins-threadpool

agent to support thread-pool and lambda

Primary LanguageJava

1. 简介

skywalking 的线程池支持插件,可以支持lamdba表达式

问: skywalking 已经提供了多线程的支持插件,为什么还要自己造轮子 答:官方提供的插件,切入点是Runnable的实现类,那如果直接写的lamdba表达式,就无法织入。

2.快速使用

2.1 开箱及食

本仓库提供的插件是基于skywalking7.0的版本,如果你用的是该版本,可以在本仓库目录/chy/plugins 下载作者已经编译好的插件。

注意: 因为要织入ThreadPool,作者这里稍稍修改了apm-agent,所以要使用我提供的apm-agent.jar作为agent的入口包 也可以在/chy/目录下找到。

apm-chy-threading-plugin-7.0.0.jar放入plugins文件夹,使用我提供的apm-agent.jar就能能够正常工作了

2.2 手动编译

如果需要二次修改那可以使用手动编译

clone本仓库到本地后,使用maven命令编译打包

mvn clean package -DskipTests -Dcheckstyle.skip=true

运行上面maven命令后,也是在项目目录下的chy文件中可以找到编译后的jar

3.效果演示

@GetMapping("/ajax/{setId}/async")
    public List<DoctorListVO> getDoctorListasync(@PathVariable Integer setId) throws ExecutionException, InterruptedException {
        
        //线程池访问
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<List<DoctorListVO>> submit = executor.submit(() -> {
            //远程调用了别的服务
            return doctorSetAdminService.queryDoctorList(setId);
        });
        Future<List<DoctorListVO>> submit2 = executor.submit(() -> {
            return doctorSetAdminService.queryDoctorList(setId);
        });

        //和上面 queryDoctorList 一样只是queryDoctorListAsy() 方法都是打了 `@Async` 注解
        doctorSetAdminService.queryDoctorListAsy(setId);
        doctorSetAdminService.queryDoctorListAsy(setId);


        List<DoctorListVO> doctorListVOS = submit.get();
        List<DoctorListVO> doctorListVOS2 = submit2.get();
        return doctorListVOS;
    }

e1

从上面可以看出,SwCallableWapper就是我插件的span标识,并且多线程可以正常追踪

4.实现原理

简单概括就是,代理了ThreadPoolExecutor类的executesubmit方法,然后替换了入参RunnableCallable成包装类

具体插件的实现细节可以看包com.chy.skywalking.apm.plugin.ttl.threading

4.1 织入 ThreadPoolExecutor的问题

因为 原生的apm-agent.jar,在bytebuddy修改ThreadPoolExecutor字节码前就已经把ThreadPoolExecutor加入到虚拟机(写入log的时候会启动线程池),导致织入失败 所以需要使用我提供的apm-agent.jar来让ThreadPoolExecutor不要过早加载

具体细节可以看 org.apache.skywalking.apm.agent.SkyWalkingAgent

主要是在WriterFactory.java中以 SnifferConfigInitializer.isPulginInitCompleted() 来控制,只有初始化之后才开始打日志。