Spring Boot default metrics
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に焦点を当てる。

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リクエストの分位数とパーセンタイル
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で生成される。

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 Space、G1 Old Gen、G1 Eden Space)で使用されたメモリを合算する。

JVMガベージコレクション指標
JVMがメモリを管理する方法について深い洞察を得るために使えるガベージコレクション指標が多数ある。大きく次の領域に分けられる。
一時停止時間
jvm_gc_pause_secondsとjvm_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を実行すると、グラフですべてのスレッド状態を確認できる。
