Skywalkingカスタム拡張スレッドプールモニタリングgrpcスレッドプール

バックグラウンド

SkyWalking Java Agent 8.10.0は、データベース接続プールとTomcatスレッドプールを監視するためのプラグインを追加します:skywalking.apache.org/events/rele…

自社のビジネスにスレッドプール監視を追加したい場合は、Skywalkingも拡張ポイントを提供します。

達成

クライアントの実装

この公式ドキュメントでは、クライアント(つまり、アプリケーション)がSkyWalkingサーバーにデータをアップロードする方法について説明します。

skywalking.apache.org/docs/skywal…

image.png

Tomcatスレッドプールの公式実装を見ると、MeterFactory.gaugeAPIが主に使用されていることがわかり、同様の記述で独自のコンポーネントでそれをシミュレートできます。

image.png

実際、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.gaugeAPIに登録しました。

これらの2つの変数に注意METER_NAMEしてTHREAD_POOL_NAME。前者はスカイウォーキングに報告した名前を表し、後者はタグタグの名前を表します。ここで適切に処理する必要があります。以前のデフォルトのTomcatと同じ名前を付けないでください。

これを定義した後、プラグインをエージェントのプラグインディレクトリにパッケージ化することに注意して、プロジェクトを開始します。

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…

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-…

おすすめ

転載: juejin.im/post/7100817655623319589