Micrometer + Promregator で Spring Boot アプリのヒストグラム形式のメトリクスを収集する際の注意点

備忘録。

CloudFoundry で動かしている Spring Boot アプリケーションのメトリクスを Promregator 経由で Prometheus に蓄積しようとした時に詰まったところ & その解決策について。

環境

  • Spring Boot アプリケーションを CloudFoundry 上で動かしている
  • HTTP で処理を受け付けて MQ に流す API と、MQ からリクエストを取り出して処理をするワーカーがある
  • API のレスポンスタイムとワーカーの処理時間のNパーセンタイルを Micrometer でメトリクス化する
  • メトリクスは Prometheus で収集する
  • インスタンス毎のメトリクスが欲しいので Prometheus server とアプリケーションの間に Promregator を挟む
  • 環境
    • Spring Boot 2.0.6
    • micrometer-registry-prometheus 1.1.1
    • Promregator 0.5.0

API とワーカーそれぞれのプロパティで percentilesHistogram にパーセンタイルを計算したいメトリクスを指定する。APIhttp.server.requests, ワーカーは spring.integration.send が共通の prefix なので、以下のようになる。

API:

management:
  metrics:
    distribution:
      percentiles-histogram:
        http.server.requests: true

ワーカー:

management:
  metrics:
    distribution:
      percentiles-histogram:
        spring.integration.send: true

起きたこと

上記の設定をした上で、Promregator のエンドポイントにリクエストして双方のメトリクスを取得すると、http_server_requests_seconds_buckets, spring_integration_send_seconds_buckets という名前のメトリクスが export されるはず。 が、spring_integration_send_seconds_buckets が取れない。

ちなみに http_server_requests_seconds_countspring_integration_seconds_count はもれなく取れる。また、API とワーカー自身が公開しているエンドポイントにリクエストするととれるべきメトリクスは全て取れる。

原因

API とワーカーで management.metrics.distribution.percentiles-histogram に指定したメトリクスがずれていたのが原因だった。

  • micrometer は percentiles-histogram が指定されたメトリクスを histogram 型として、それ以外のメトリクスを summary 型として export する
  • Promregator では対象アプリケーションのエンドポイントをリクエストした際、# TYPE コメントを元にメトリクスの型(counter, gauge, histogram, summary)をパースする
  • Promregator は複数のエンドポイント間で同じメトリクスに異なる型が混在していた場合、後から収集したメトリクスについては WARN メッセージを出力してスキップする

今回のケースだと、API は MQ への publish をするため、自動的に spring_integration_send から始まるメトリクスを export するが、percentiles-histogram の指定はされていないので summary 型として export する。

# TYPE spring_integration_send_seconds summary
...

一方、ワーカーでは spring_integration_sendpercentiles-histogram に含まれているので、histogram 型として出力する。

# TYPE spring_integration_send_seconds histogram
...

この型の不一致によって、ワーカーの spring_integration_send_seconds_buckets が Promregator のエンドポイントにリクエストした際に含まれていなかった。ログを見るとその旨が出ている。

Attempt to merge metric spring_integration_send_seconds, but types are deviating: ...

解決策

解決するためには2つのアプリケーション間で percentiles-histogram に含めるメトリクスを共通にすればいい。

management:
  metrics:
    distribution:
      percentiles-histogram:
        http.server.requests: true
        spring.integration.send: true

これによってどちらのアプリケーションでもメトリクスが histogram 型となり、上記の問題を回避できる。

ただしこれだと興味のないメトリクスもエクスポートされることになる……
(アプリケーション間でメトリクス名に共通の prefix or suffix を付けられるといいのだけど、そこはまだ未調査)