MicrometerでExecutorServiceのメトリクスを収集する #micrometer
前回書いた Spring BootアプリのメトリクスをMicrometerで収集する の続きです。
この記事では、java.util.concurrent.ExecutorService
のメトリクスを収集するためのExecutorServiceMetricsを紹介します。
なお、この記事で使用しているバージョンは以下です。
(2018/05/28現在の最新)
- Spring Boot: 2.0.2 or 1.5.13
- Spring Boot
- spring-boot-starter-actuator
- Micrometer: 1.0.4
- micrometer-core
- micrometer-spring-legacy ※Spring Boot 1.5の場合は必須
- micrometer-registry-prometheus ※僕はモニタリングにPrometheusを使っています
ExecutorServiceに関するメトリクスは自動で収集されないので、自分で設定を行う必要がありますが、設定は簡単です。
自分で作成したExecutorService
を引数にしてExecutorServiceMetrics#monitor
を呼ぶと、メトリクス収集処理が仕込まれたExecutorServiceが取得できるので、それ使うだけでメトリクスが収集されます。
コード例
@Service
public class AsyncService {
private final ExecutorService instrumentedExecutor;
public AsyncService(MeterRegistry registry) {
ExecutorService executor = Executors.newFixedThreadPool(10); // ここはお好みで
instrumentedExecutor = ExecutorServiceMetrics.monitor(registry, executor, "MyThreadPool");
}
public void doSomething() {
// ExecutorServiceとして使うだけでメトリクスが収集される
instrumentedExecutor.execute(() -> {
log.info("Thread name = {}", Thread.currentThread().getName());
});
}
}
AsyncConfigurerSupportの場合
また、Spring MVCには@Async
アノテーションを付けたクラス・メソッドを非同期に処理する機能があり、
AsyncConfigurerSupport
を継承したクラスを作ると、@Async
で使用されるThreadPoolをカスタマイズする事ができます。
@Async
とAsyncConfigurerSupport
に関しては以下の記事がわかりやすいです。
コード例
AsyncConfigurerSupportを継承したクラスで、上記の例と同じようにExecutorServiceMetrics#monitor
でメトリクス収集処理が仕込まれたExecutorServiceを取得して、getAsyncExecutorでreturnします。
@Configuration
@EnableAsync
public class AsyncConfig extends AsyncConfigurerSupport {
private final ExecutorService asyncExecutor;
public AsyncConfig() {
final ExecutorService executor = Executors.newFixedThreadPool(10); // ここはお好みで
// see:
// https://github.com/micrometer-metrics/micrometer/blob/v1.0.4/micrometer-spring-legacy/src/test/java/io/micrometer/spring/async/ThreadPoolTaskExecutorMetricsIntegrationTest.java#L61-L62
asyncExecutor = ExecutorServiceMetrics.monitor(Metrics.globalRegistry, executor, "MyThreadPool");
}
@Override
public Executor getAsyncExecutor() {
return asyncExecutor;
}
}
※注意点
AsyncConfigurerSupport
の場合、ExecutorServiceMetrics#monitor
に渡すMeterRegistry
はDIで受け取ったインスタンスではなく、Metrics.globalRegistry
を使わないといけません。
ドキュメントに記載は見当たらなかったのですが、テストコードに以下のようにコメントが書いてあります。
Injecting the registry instead would cause early evaluation of the registry and the registry wouldn’t be discovered by MeterRegistryPostProcessor
Spring内部の処理順序の関係で、Metrics.globalRegistry
を使わないとExecutorServiceMetricsが正しく動作しません。
収集されるメトリクス
- ThreadPoolのメトリクス
- Queued
- Active
- Poolサイズ
- タスクのメトリクス
- Completed
などが収集されます。
# HELP executor_queued_threads The approximate number of threads that are queued for execution
# TYPE executor_queued_threads gauge
executor_queued_threads{name="MyThreadPool",} 0.0
# HELP executor_active_threads The approximate number of threads that are actively executing tasks
# TYPE executor_active_threads gauge
executor_active_threads{name="MyThreadPool",} 10.0
# HELP executor_pool_size_threads The current number of threads in the pool
# TYPE executor_pool_size_threads gauge
executor_pool_size_threads{name="MyThreadPool",} 10.0
# HELP executor_completed_tasks_total The approximate total number of tasks that have completed execution
# TYPE executor_completed_tasks_total counter
executor_completed_tasks_total{name="MyThreadPool",} 40.0
以上です。