バックグラウンド
SkyWalking Java Agent 8.10.0は、データベース接続プールとTomcatスレッドプールを監視するためのプラグインを追加します: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.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…
意思就是,如果需要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关键字,就可以看到我们之前定义的名字:
选中指标,然后点击选择图形样式,再输入面板的自定义名称,最后点击确认即可:
最后客户端上报数据后,该面板将实时展示数据: