Spring Boot default metrics

Spring Boot 2のActuatorモジュールは、アプリケーションの監視および管理機能を提供し、Micrometerメトリクス収集機能を含んでいる。Micrometerは多くの有用な基本メトリクスが事前構成された状態で提供され、ユーザーが直接構成できる機能も含んでいる。

https://tomgregory.com/spring-boot-default-metrics/

ここではSpring Bootで提供される最も重要な基本メトリクスと、それを使用してアプリケーション内の問題をより効果的に強調する方法を見ていく。

Spring Boot ActuatorとMicrometerの概要

Spring Boot ActuatorはHTTPおよびJMXを通じて、さまざまな監視・管理エンドポイントを提供する。Micrometerアプリケーション監視フレームワークと統合することで、非常に重要なメトリクス機能が含まれる。

Micrometerサイトのトップページには次のような内容がある。

Micrometer provides a simple facade over the instrumentation clients for the most popular monitoring systems, allowing you to instrument your JVM-based application code without vendor lock-in. Think SLF4J, but for metrics.

Micrometerはベンダーに依存しないmetrics facadeである。つまり、1つの共通方法でメトリクスを収集し、さまざまな監視システムが要求する形式で公開する。ロギング関連システムにSLF4Jがあるなら、監視(metric)システムにはMicrometerがある。

サポートされる人気の監視フレームワークにはGraphite、Prometheus、StatsDがある。ここでは、アプリケーションから周期的にメトリクスを取得する独立サービスであるPrometheusに焦点を当てる。

Prometheus pull

Spring BootアプリケーションにActuatorメトリクスを追加する

Prometheus形式でメトリクスを公開するようSpring Bootアプリケーションを構成するには、次の手順に従う。

追加依存関係を含める

Spring Boot Starter Actuator モジュールを含めるには、Gradle依存関係一覧に次を追加する。

implementation 'org.springframework.boot:spring-boot-starter-actuator'

Mavenでは次のようになる。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

そしてMicrometer Registry Prometheus モジュールを追加し、アプリケーションからPrometheus形式でメトリクスをスクレイプできるようにする。

Gradle:

implementation 'io.micrometer:micrometer-registry-prometheus:1.5.1'

Maven:

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
    <version>1.5.1</version>
</dependency>

構成でメトリクス有効化を設定する

デフォルトでは、ほぼすべてのSpring Boot Actuator HTTPエンドポイントは無効化されているが、構成によって有効化できる。プロジェクトのsrc/main/resourcesフォルダにあるapplication.propertiesファイルへ次の設定を追加する。

management.endpoints.web.exposure.include=metrics,prometheus

Actuatorモジュールには有効化できるエンドポイントが多いが、この構成では次の2つだけを有効化した。

  • /actuator/metrics: メトリクスを探索し、その値を見るためのJSON APIを提供するエンドポイント。
  • /actuator/prometheus: Prometheusで収集するために必要なカスタム形式でメトリクスを返すエンドポイント。
    • ここが今後説明していく内容である。

1. Spring MVCメトリクス

すべてのWebアプリケーションにおいて、基本Spring MVCメトリクスはインバウンドHTTPトラフィックを監視するための優れた開始点を提供する。エラー、トラフィック量、リクエスト遅延時間のいずれを追跡する必要がある場合でも、これらのメトリクスで確認できる。

インバウンドHTTPリクエスト期間

Spring Bootアプリケーションで公開される各エンドポイントについて、リクエスト数とリクエスト期間に関する情報を提供するhttp_server_requests_seconds summaryメトリクスを得られる。これは/actuator/prometheusエンドポイントに公開される2つのメトリクスで構成される。

# HELP http_server_requests_seconds  
# TYPE http_server_requests_seconds summary
http_server_requests_seconds_count{exception="None",method="GET",outcome="SUCCESS",status="200",uri="/hello",} 12.0
http_server_requests_seconds_sum{exception="None",method="GET",outcome="SUCCESS",status="200",uri="/hello",} 0.083579374
  • http_server_requests_seconds_countは、アプリケーションがそのエンドポイントで受け取った総リクエスト数である。
  • http_server_requests_seconds_sumは、アプリケーションがそのエンドポイントで受け取った全リクエスト期間の合計である。

これらのメトリクスには次のタグが含まれる。

Tag 説明
exception 発生した例外のクラス名 None, NullPointerException
method HTTPリクエスト方法 GET, POST, PUT, PATCHなど
outcome HTTPレスポンス状態の文字列表現 SUCCESS, SERVER_ERROR
status HTTPレスポンスステータスコード 200, 500など
uri リクエストURI /hello

Prometheusでは、すべてのタグに対する平均インバウンドリクエスト期間を提供する簡単なクエリを作成できる。

rate(http_server_requests_seconds_sum[1m]) / rate(http_server_requests_seconds_count[1m])

http_server_requests_seconds_count / http_server_requests_seconds_sumグラフ

インバウンドHTTPリクエストの分位数とパーセンタイル

Spring MVCメトリクスは分位数とパーセンタイルも計算できる。これは最も遅いリクエストを無視しながら、APIのリクエスト期間がどれほど遅いか評価したい場合に有用である。

たとえば95パーセンタイルは、観測値の95%が下にあり、5%が上にある値である。つまり、リクエストの95%で見られる最も遅いリクエスト期間を提供する。

分位数を有効にするには、関心のある分位数を指定した追加設定プロパティをapplication.propertiesに追加する。

management.metrics.web.server.request.autotime.percentiles=<comma-separated list of quantiles>

プロパティを0.95に構成すると、/actuator/prometheusで次のようなメトリクスが生成される。

http_server_requests_seconds{exception="None",method="GET",outcome="SUCCESS",status="200",uri="/hello",quantile="0.95",} 0.023068672

このメトリクスで使用されるタグは上と同じだが、メトリクスをクエリするために使えるquantileタグも追加される。

http_server_requests_seconds{quantile="0.95"}クエリでPrometheusにグラフが生成される。

インバウンドHTTPリクエスト最大期間

Spring Bootアプリケーションが公開する各エンドポイントについて、各インバウンドHTTPリクエストタイプの最大持続時間を提供するhttp_server_requests_seconds_max gaugeメトリクスを得られる。

# HELP http_server_requests_seconds_max Duration of HTTP server request handling
# TYPE http_server_requests_seconds_max gauge
http_server_requests_seconds_max{exception="None",method="GET",outcome="SUCCESS",status="200",uri="/hello",} 0.005831
  • http_server_requests_seconds_maxは期間中の最大リクエスト期間である。新しい時間ウィンドウが始まると値は0にリセットされる。デフォルト時間ウィンドウは2分である。

このメトリクスで使用されるタグは上と同じである。

このグラフは通常のhttp_server_requests_seconds_maxクエリからPrometheusで生成される。

http_server_requests_seconds_maxグラフ

2. HTTPクライアントRestTemplateおよびWebClientアウトバウンドリクエストメトリクス

RestTemplateまたはWebClientクラスを使用してアウトバウンドHTTPリクエストを実行する場合、インバウンドHTTPリクエストと同様のリクエストメトリクスを使用できる。これらのメトリクスが動作するには、注入されたRestTemplateBuilderまたはWebClient.Builderクラスを使用してHTTPクライアントを作成する必要がある。

アウトバウンドHTTPリクエスト期間

各アウトバウンドエンドポイントはhttp_client_requests_secondsメトリクスを取得する。これは/actuator/prometheusエンドポイントによって公開される2つのメトリクスで構成される。

# HELP http_client_requests_seconds Timer of RestTemplate operation
# TYPE http_client_requests_seconds summary
http_client_requests_seconds_count{clientName="google.com",method="GET",outcome="SUCCESS",status="200",uri="/https://google.com",} 3.0
http_client_requests_seconds_sum{clientName="google.com",method="GET",outcome="SUCCESS",status="200",uri="/https://google.com",} 0.465022459
  • http_client_requests_seconds_countは、アプリケーションがこのエンドポイントに対して実行した総リクエスト数である。
  • http_client_requests_seconds_sumは、アプリケーションがこのエンドポイントに対して実行した全リクエスト期間の合計である。

これらのメトリクスには次のタグも含まれる。

タグ 説明
clientName URIのホストを使用して呼び出すエンドポイント名
exception 発生した例外のクラス名
method HTTPリクエスト方法
outcome HTTPレスポンス状態の文字列表現
status HTTPレスポンスステータスコード
uri リクエストURI

Prometheusでは、時間経過に伴う平均アウトバウンドリクエスト期間を提供する簡単なクエリを作成できる。

rate(http_client_requests_seconds_sum[1m]) / rate(http_client_requests_seconds_count[1m])

アウトバウンドHTTPリクエスト最大期間

各アウトバウンドエンドポイントはhttp_client_requests_seconds_max gauge指標を取得し、各アウトバウンドHTTPリクエストタイプの最大持続時間を提供する。

# HELP http_client_requests_seconds_max Timer of RestTemplate operation
# TYPE http_client_requests_seconds_max gauge
http_client_requests_seconds_max{clientName="google.com",method="GET",outcome="SUCCESS",status="200",uri="/https://google.com",} 0.205564498
  • http_client_requests_seconds_maxは期間中の最大リクエスト期間である。新しい時間ウィンドウが始まると値は0にリセットされる。デフォルト時間ウィンドウは2分である。

このメトリクスで使用されるタグは上の「アウトバウンドHTTPリクエスト期間」と同じである。

3. JVMメトリクス

Micrometerには、JVM(Java Virtual Machine)で発生している状況の監視に役立つ3種類のメトリクスが含まれている。

JVMメモリメトリクス

各メモリ領域について、jvm_memory_used_bytesで使用済みメモリ量を、jvm_memory_max_bytesで使用可能メモリ量を確認できる。

# HELP jvm_memory_used_bytes The amount of used memory
# TYPE jvm_memory_used_bytes gauge
jvm_memory_used_bytes{area="heap",id="G1 Survivor Space",} 8388608.0
jvm_memory_used_bytes{area="heap",id="G1 Old Gen",} 3938936.0
jvm_memory_used_bytes{area="nonheap",id="Metaspace",} 4.2306152E7

...

# HELP jvm_memory_max_bytes The maximum amount of memory in bytes that can be used for memory management
# TYPE jvm_memory_max_bytes gauge
jvm_memory_max_bytes{area="heap",id="G1 Survivor Space",} -1.0
jvm_memory_max_bytes{area="heap",id="G1 Old Gen",} 8.589934592E9

ここには多くのデータがあるが、たとえばPrometheusで次のクエリを使用し、使用されたheap type memoryの総量を表示できる。

sum(jvm_memory_used_bytes{area="heap"})

これはPrometheusのsum関数を使用し、上のidタグで見られるすべてのヒープメモリ領域(G1 Survivor SpaceG1 Old GenG1 Eden Space)で使用されたメモリを合算する。

使用済みヒープメモリを表示するためにjvm_memory_used_bytesをグラフ化

JVMガベージコレクション指標

JVMがメモリを管理する方法について深い洞察を得るために使えるガベージコレクション指標が多数ある。大きく次の領域に分けられる。

一時停止時間

jvm_gc_pause_secondsjvm_gc_pause_seconds_maxメトリクスは、ガベージコレクションに費やされた時間に関する情報を提供する。

# HELP jvm_gc_pause_seconds Time spent in GC pause
# TYPE jvm_gc_pause_seconds summary
jvm_gc_pause_seconds_count{action="end of minor GC",cause="Metadata GC Threshold",} 1.0
jvm_gc_pause_seconds_sum{action="end of minor GC",cause="Metadata GC Threshold",} 0.005
# HELP jvm_gc_pause_seconds_max Time spent in GC pause
# TYPE jvm_gc_pause_seconds_max gauge
jvm_gc_pause_seconds_max{action="end of minor GC",cause="Metadata GC Threshold",} 0.0

メモリプールサイズ増加

jvm_gc_memory_allocated_bytes_total指標はyoung generation memory poolのサイズ増加を知らせ、jvm_gc_memory_promoted_bytes_totalメトリクスはold generationに関するものである。

ライブold generation poolサイズ

jvm_gc_live_data_size_bytesメトリクスはold generation poolサイズを知らせる。jvm_gc_max_data_size_bytesはold generation poolに割り当て可能な最大サイズを知らせる。

JVMスレッドメトリクス

これらの指標により、JVM内のスレッドを確認できる。

# HELP jvm_threads_states_threads The current number of threads having NEW state
# TYPE jvm_threads_states_threads gauge
jvm_threads_states_threads{state="runnable",} 7.0
jvm_threads_states_threads{state="blocked",} 0.0
jvm_threads_states_threads{state="waiting",} 11.0
jvm_threads_states_threads{state="timed-waiting",} 3.0
jvm_threads_states_threads{state="new",} 0.0
jvm_threads_states_threads{state="terminated",} 0.0
  • jvm_threads_states_threadsは各スレッド状態にあるスレッド数を示す。
  • jvm_threads_live_threadsはデーモンおよび非デーモンスレッドを含む総ライブスレッド数を示す。
  • jvm_threads_daemon_threadsは総デーモンスレッド数を示す。
  • jvm_threads_peak_threadsはJVM起動後の最大総スレッド数を示す。

Prometheusでjvm_threads_states_threadsを実行すると、グラフですべてのスレッド状態を確認できる。

jvm_threads_states_threadsグラフ