Prometheusのヒストグラムはなぜ累積的か? - Prometheusドキュメント

このページはPrometheus公式ドキュメント和訳+αの一部です。

Why are Prometheus histograms cumulative?

なぜヒストグラムバケットが、単に各バケットに入ったイベントのカウンターではないのか考えたことはあるだろうか?

例えば、レイテンシーを記録するためのデフォルトのバケットヒストグラムがあり、0.04s、0.2s、0.3s、1s、5sのサイズのイベントを観測したとする。 テキスト形式の出力は以下のようになるだろう。

# HELP example_latency_seconds Some help text
# TYPE example_latency_seconds histogram
example_latency_seconds_bucket{le="0.005"} 0.0
example_latency_seconds_bucket{le="0.01"} 0.0
example_latency_seconds_bucket{le="0.025"} 0.0
example_latency_seconds_bucket{le="0.05"} 1.0
example_latency_seconds_bucket{le="0.075"} 1.0
example_latency_seconds_bucket{le="0.1"} 1.0
example_latency_seconds_bucket{le="0.25"} 2.0
example_latency_seconds_bucket{le="0.5"} 3.0
example_latency_seconds_bucket{le="0.75"} 3.0
example_latency_seconds_bucket{le="1.0"} 4.0
example_latency_seconds_bucket{le="2.5"} 4.0
example_latency_seconds_bucket{le="5.0"} 5.0
example_latency_seconds_bucket{le="7.5"} 5.0
example_latency_seconds_bucket{le="10.0"} 5.0
example_latency_seconds_bucket{le="+Inf"} 5.0
example_latency_seconds_count 5.0
example_latency_seconds_sum 6.54

0.05のバケットには、期待通りに、1つのサンプルがある。 0.25のバケットには、0.1 < x <= 0.25の範囲に1つのサンプルしかないにも関わらず、2つのサンプルがある。 これは、leがless than or equal toの略であり、各バケットはそれ以下のサンプルを含んでいるからである。 したがって、+Infのバケットは、サンプル数の合計(_countと等しい)となる。

このことが、ヒストグラムが累積的でないと期待している人を驚かせることがある。 では、なぜ、直感的な非累積的なヒストグラムの代わりに、累積的なヒストグラムを使うのか?

The answer is operational. ラベルがあれば常に要素数を一緒に考えなければならない。 ヒストグラムは、デフォルトで、バケットの数が10である。 もし、ヒストグラムにさらにラベルを追加したり、さらにバケットを追加すると、ヒストグラムのコストがかなり高くなる可能性がある。 ヒストグラムが累積的であるということは、Prometheusに取り込む際に、いくつかのバケットdropすることができるということである。 (いくらか不正確だが)分位数の計算を可能としつつPrometheusのコストを減らすことになる。 これによって、アプリケーションのコードをバケット数が減るように修正するための時間を稼ぐことができる。

例えば、100ms以下のバケットを全てなくしたいとすると、以下のリラベルの設定が利用できるだろう。

scrape_configs:
 - job_name: 'my_job'
   static_configs:
     - targets:
       - my_target:1234
   metric_relabel_configs:
   - source_labels: [ __name__, le ]
     regex: 'example_latency_seconds_bucket;(0\.0.*)'
     action: drop

好きなだけ多くのまたは少しのバケットdropすることができるが、+Infのバケットhistogram_quantileのために必要である。

ヒストグラム_sum_countがあるのは、ヒストグラムの要素数が多くなり過ぎる可能性があるためでもある。 もし、全てのバケットの時系列をdropしても、その2つの時系列だけから平均レイテンシーを計算することができる。

さらに、この方法のおかげで、あるバケット以下のイベントの比率を計算するのも簡単になる。 例えば、1s以下のイベントの比率は以下の式で計算できる。

example_latency_seconds_bucket{le="1.0"}
/ ignoring (le)
example_latency_seconds_bucket{le="+Inf"}

翻訳元

おすすめ書籍

入門 Prometheus ―インフラとアプリケーションのパフォーマンスモニタリング

入門 Prometheus ―インフラとアプリケーションのパフォーマンスモニタリング

 
入門 監視 ―モダンなモニタリングのためのデザインパターン

入門 監視 ―モダンなモニタリングのためのデザインパターン

 
SRE サイトリライアビリティエンジニアリング ―Googleの信頼性を支えるエンジニアリングチーム

SRE サイトリライアビリティエンジニアリング ―Googleの信頼性を支えるエンジニアリングチーム