Skywalking custom extended thread pool monitoring grpc thread pool

background

SkyWalking Java Agent 8.10.0 adds a plugin for monitoring database connection pool and tomcat thread pool: skywalking.apache.org/events/rele…

If we want to add some thread pool monitoring for our own business, Skywalking also provides expansion points.

accomplish

Client implementation

This official document describes how the client (that is, the application) uploads data to the SkyWalking server.

skywalking.apache.org/docs/skywal…

image.png

By looking at the official implementation of the tomcat thread pool, we can see that the MeterFactory.gaugeAPI is mainly used, and we can simulate it in our own components with similar writing.

image.png

Judging from the interception source code of the tomcat thread pool, in fact, the core principle is to intercept the Java thread pool object in a suitable place, and then obtain the corresponding status by calling the getXxxSize of the thread pool object, and then report it.

Because my requirement here is to monitor the business thread pool when grpc is running, first I need to write my client plug-in to get the grpc business thread pool and call it for status monitoring. My source code is as follows:

Define the interception class. I intercept it here at ServerImpl.start, that is, when the grpc service starts, and obtain the thread pool:

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);
    }

}
复制代码

In my interception class, I obtained the executor attribute in the ServerImpl class through reflection, which is the business thread pool, and then registered it in the MeterFactory.gauge API,

Note METER_NAMEand THREAD_POOL_NAMEthese two variables, the former represents the name you reported to Skywalking, and the latter represents the name of the tag tag. It should be handled well here. Do not have the same name as the previous default tomcat.

After defining this, pay attention to package the plugin into the plugin directory of the agent, and start the project.

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 server implementation

注意,plugin中写好了自己的上报程序后,服务端还是需要做出配置的,否则上报上去的数据无法被加载到。

skywalking.apache.org/docs/main/l…

image.png

意思就是,如果需要SkyWalking收集更多的信息,需要在 meterAnalyzerActiveFiles 中配置,SkyWalking在启动时会加载其中的内容:

SkyWalking内置了下面4个收集,grpc是我后面根据thread pool加的。

image.png

thread pool内容如下:

image.png

我定义的grpc thread pool内容如下,其实就是拷贝了一份,然后修改了 metricsRules 中的 name:

image.png

最后需要在截图中的application.yaml的meterAnalyzerActiveFiles中添加上我们自定义的grpcthreadpool.yaml

image.png

image.png

(其实这一步不用新加文件也可以,我们可以将我们自己的线程信息也定义在threadpool.yaml中):

image.png

最后重启你的SkyWalking后端,以及启动的你的应用程序,在SkyWalking提供的界面中做出配置:

点击普通服务,然后点击你的服务名字进入下一个页面:

image.png

进入instance页面后,点击相应的instance:

image.png

然后进入JVM的Tab,开启编辑模式,即右上角那个蓝色的按钮,默认是灰色的,点击一下就成了蓝色,然后点击左边按钮,再点击Add Widget,就会出现大箭头的无图表:

image.png

再点击无图标右上方的三个点,再点击弹出的编辑按钮,在弹出的页面中,指标该项,输入grpc关键字,就可以看到我们之前定义的名字:

image.png

选中指标,然后点击选择图形样式,再输入面板的自定义名称,最后点击确认即可:

image.png

最后客户端上报数据后,该面板将实时展示数据:

image.png

image.png

本文参考了:developpaper.com/skywalking-…

Guess you like

Origin juejin.im/post/7100817655623319589