背景
SkyWalking Java Agent 8.10.0 增加了对database连接池和tomcat线程池监控的plugin:skywalking.apache.org/events/rele…
如果我们自己想增加一些针对于自己业务的线程池的监控,Skywalking也是提供了拓展点的。
实现
客户端实现
这篇官方文档描述了客户端(也就是应用端)如何上传数据到SkyWalking服务端。
skywalking.apache.org/docs/skywal…
通过查看官方对tomcat线程池的实现,可以看到主要使用了 MeterFactory.gauge
API,我们可以在我们自己的组件中也用类似的写法进行模拟一下。
通过对tomcat线程池的拦截源码来看,其实核心原理就是在合适的地方拦截到Java线程池对象,然后通过调用线程池对象的getXxxSize来获取到相应的状态,然后上报,
因为我这里的需求是监控grpc运行时的业务线程池,所以首先我需要先编写我的客户端插件,用于取到grpc业务线程池,并对其进行状态监控调用,我的源代码如下:
定义拦截类,我这里是在ServerImpl.start,也就是grpc服务启动的时候进行拦截,获取线程池:
public class GrpcThreadPoolInstrumentation extends ClassEnhancePluginDefine {
// 代理类
public static final String INTERCEPT_CLASS =
"org.apache.skywalking.apm.plugin.grpc.v1.server.GrpcDefaultThreadExecutorInterceptor";
// 需要拦截的方法
public static final String ENHANCE_METHOD = "start";
// 需要拦截的类
public static final String ENHANCE_CLASS = "io.grpc.internal.ServerImpl";
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[]{new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named(ENHANCE_METHOD);
}
@Override
public String getMethodsInterceptor() {
return INTERCEPT_CLASS;
}
@Override
public boolean isOverrideArgs() {
return false;
}
}};
}
@Override
public StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() {
return new StaticMethodsInterceptPoint[0];
}
@Override
protected ClassMatch enhanceClass() {
return byName(ENHANCE_CLASS);
}
}
复制代码
我的拦截类里通过反射获取到ServerImpl类中的 executor 属性,该属性就是业务线程池,然后将其注册到 MeterFactory.gauge API中,
注意 METER_NAME
和 THREAD_POOL_NAME
这两个变量,前者代表你上报到Skywalking中的名字,后者代表tag标签的名字,这里要处理好,不要和之前默认的tomcat重名,
定义好这个后,注意将plugin打包放到agent的plugin目录下,启动项目即可。
public class GrpcDefaultThreadExecutorInterceptor implements InstanceMethodsAroundInterceptor {
private static final String METER_NAME = "grpc_thread_pool";
private static final String METRIC_POOL_NAME_TAG_NAME = "pool_name";
private static final String THREAD_POOL_NAME = "grpc_default_executor";
private static final String METRIC_TYPE_TAG_NAME = "metric_type";
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
MethodInterceptResult result) throws Throwable {
}
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
Object ret) throws Throwable {
Field field = ret.getClass().getDeclaredField("executor");
field.setAccessible(true);
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) field.get(ret);
MeterFactory.gauge(METER_NAME, () -> (double) threadPoolExecutor.getCorePoolSize())
.tag(METRIC_POOL_NAME_TAG_NAME, THREAD_POOL_NAME)
.tag(METRIC_TYPE_TAG_NAME, "core_pool_size")
.build();
MeterFactory.gauge(METER_NAME, () -> (double) threadPoolExecutor.getMaximumPoolSize())
.tag(METRIC_POOL_NAME_TAG_NAME, THREAD_POOL_NAME)
.tag(METRIC_TYPE_TAG_NAME, "max_pool_size")
.build();
MeterFactory.gauge(METER_NAME, () -> (double) threadPoolExecutor.getPoolSize())
.tag(METRIC_POOL_NAME_TAG_NAME, THREAD_POOL_NAME)
.tag(METRIC_TYPE_TAG_NAME, "pool_size")
.build();
MeterFactory.gauge(METER_NAME, () -> (double) threadPoolExecutor.getQueue().size())
.tag(METRIC_POOL_NAME_TAG_NAME, THREAD_POOL_NAME)
.tag(METRIC_TYPE_TAG_NAME, "queue_size")
.build();
MeterFactory.gauge(METER_NAME, () -> (double) threadPoolExecutor.getActiveCount())
.tag(METRIC_POOL_NAME_TAG_NAME, THREAD_POOL_NAME)
.tag(METRIC_TYPE_TAG_NAME, "active_size")
.build();
return ret;
}
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Throwable t) {
}
}
复制代码
SkyWalking服务端实现
注意,plugin中写好了自己的上报程序后,服务端还是需要做出配置的,否则上报上去的数据无法被加载到。
skywalking.apache.org/docs/main/l…
意思就是,如果需要SkyWalking收集更多的信息,需要在 meterAnalyzerActiveFiles 中配置,SkyWalking在启动时会加载其中的内容:
SkyWalking内置了下面4个收集,grpc是我后面根据thread pool加的。
thread pool内容如下:
我定义的grpc thread pool内容如下,其实就是拷贝了一份,然后修改了 metricsRules 中的 name:
最后需要在截图中的application.yaml的meterAnalyzerActiveFiles中添加上我们自定义的grpcthreadpool.yaml
(其实这一步不用新加文件也可以,我们可以将我们自己的线程信息也定义在threadpool.yaml中):
最后重启你的SkyWalking后端,以及启动的你的应用程序,在SkyWalking提供的界面中做出配置:
点击普通服务,然后点击你的服务名字进入下一个页面:
进入instance页面后,点击相应的instance:
然后进入JVM的Tab,开启编辑模式,即右上角那个蓝色的按钮,默认是灰色的,点击一下就成了蓝色,然后点击左边按钮,再点击Add Widget,就会出现大箭头的无图表:
再点击无图标右上方的三个点,再点击弹出的编辑按钮,在弹出的页面中,指标该项,输入grpc关键字,就可以看到我们之前定义的名字:
选中指标,然后点击选择图形样式,再输入面板的自定义名称,最后点击确认即可:
最后客户端上报数据后,该面板将实时展示数据:
本文参考了:developpaper.com/skywalking-…
作者:🐳🐳🐳阿布
链接:https://juejin.cn/post/7100817655623319589/
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。