Micrometer metrics を用いたメトリクス収集

Estimated reading time: 1 minute

Metrics feature を用いると Metrics を構成してサーバとリクエストに関する 情報を取得できます。 この実装は JRE 8 以降と Micrometer Metrics を使用しています。

This feature is defined in the class io.ktor.metrics.micrometer.MicrometerMetrics in the artifact io.ktor:ktor-metrics-micrometer:$ktor_version.
dependencies { implementation "io.ktor:ktor-metrics-micrometer:$ktor_version" }
dependencies { implementation("io.ktor:ktor-metrics-micrometer:$ktor_version") }
<project> ... <dependencies> <dependency> <groupId>io.ktor</groupId> <artifactId>ktor-metrics-micrometer</artifactId> <version>${ktor.version}</version> <scope>compile</scope> </dependency> </dependencies> </project>

メトリクスの出力

利用したい時系列データベースによりますが、ここでは vary の 命名規則に従います。

ktor.http.server.requests.active

アクティブ gauge は、 サーバへの同時HTTPリクエスト数をカウントします。 このメトリクスにはタグはありません。

ktor.http.server.requests

timer は各リクエストのレスポンスタイムを測定します。 この feature は、次のタグを提供します。

  • address: リクエスト元のクライアントの <host>:<port>
  • method: HTTP メソッド (GETPOST など)
  • route: ktor がハンドリングするリクエストパス (/vehicles/23847/tires/frontright のパス /vehicles/{id}/tires/{tire} など)
  • status: クライアントへ送出した HTTP ステータスコード (200404 など)
  • exception: ハンドラがクライアントへ応答する前に Exception や Throwable をスローした場合、例外の名前または n/a
    クライアントへの応答後にスローされた例外は記録されません。

インストール

Metrics feature を利用する場合は、利用したい MeterRegistry を指定する必要があります。 テスト利用の場合は SimpleMeterRegistry を利用します。 より実践的なものを利用する場合は、 any registry depending on your timeline database vendor から 選択してください。

install(MicrometerMetrics) {
   registry = SimpleMeterRegistry()
}

Meter Binders

Micromerter は低レイヤのメトリクスも収集します。 このメトリクスは MeterBinder から提供されます。 デフォルトではこれらのメトリクスを収集しますが、これらのメトリクスを収集したくない場合や他のメトリクスを収集したい場合は、 meterBinders を再定義します。 (メトリクスを収集したくない場合は空リストを指定します)

install(MicrometerMetrics) {
   registry = SimpleMeterRegistry()
   meterBinders = listOf(
            ClassLoaderMetrics(),
            JvmMemoryMetrics(),
            JvmGcMetrics(),
            ProcessorMetrics(),
            JvmThreadMetrics(),
            FileDescriptorMetrics()
   )
}

分布統計の設定

Micrometer はいろいろなヒストグラムの表現方法を提供します。 クライアントサイドにてパーセンタイルやヒストグラムカウンタで表現できます。 (時系列データベースはサーバサイドでパーセンタイルを計算します。) パーセンタイルはすべてのバックエンドでサポートされていますが、 メモリ効率が悪い ため多次元での集計ができません。 ヒストグラムでは対応できますが、全てのバックエンドでサポートされているとは限りません。 詳細はこちらを参照してください。

デフォルトでは、タイマーは50%、90%、95%、99%パーセンタイルを提供します。 DistributionStatisticConfig feature をタイマーに適用することで、独自の設定が可能になります。

install(MicrometerMetrics) {
    registry = PrometheusMeterRegistry(PrometheusConfig.DEFAULT)
    
    distributionStatisticConfig = DistributionStatisticConfig.Builder()
                .percentilesHistogram(true)
                .maximumExpectedValue(Duration.ofSeconds(20).toNanos())
                .sla(
                    Duration.ofMillis(100).toNanos(),
                    Duration.ofMillis(500).toNanos()
                )
                .build()
}

タイマーのカスタマイズ

各タイマーのタグをカスタマイズするには、各リクエストごとに呼び出されるラムダ関数を作成し、 タイマーのビルダーを用いて適用します。 タグの値の組み合わせごとに独自のメトリクスが生成されることに注意してください。 そのため、カーディナリティの高い値 (リソースIDなど) をタグに指定することは非推奨です。

install(MicrometerMetrics) {
    registry = PrometheusMeterRegistry(PrometheusConfig.DEFAULT)
    
    timers { call, exception ->
        this.tag("tenant", call.request.headers["tenantId"])
    }
}