# なぜヒストグラムなのか？

Site [llms.txt](/ja/llms.txt)

---

ヒストグラムは、データポイントの分布を要約するマルチバリューカウンターです。
たとえば、ヒストグラムには、負の値、正の値、ゼロの値の出現回数をそれぞれカウントする3つのカウンターがあるかもしれません。
数値の系列 `3`、`-9`、`7`、`6`、`0`、`-1` が与えられた場合、ヒストグラムは負の値が `2`、ゼロが `1`、正の値が `3` とカウントします。
単一のヒストグラムデータポイントは、最も一般的に棒グラフとして表現されます。

![ヒストグラムポイントの棒グラフ](hist-point.png "A single histogram point plotted as a bar chart with 3 buckets titled 'Positivity of numbers'. The first bucket shows negative numbers and has a height of 2. The second bucket shows zero values and has a height of 1. The third bucket shows positive values and has a height of 3.")

上の例では出力値が3つしかありませんが、単一のヒストグラムにはもっと多くの値があるのが一般的です。
実際のアプリケーションでは通常、前の1分間のメトリクスを要約したヒストグラムを毎分エクスポートします。
このようにヒストグラムを使うことで、データの分布が時間の経過とともにどのように変化するかを調べることができます。

## ヒストグラムは何のためにあるのか？ {#what-are-histograms-for}

ヒストグラムには多くの用途がありますが、その力はデータの分布に関するクエリに効率的に回答できる能力にあります。
これらのクエリは、最も一般的には「過去1分間のレスポンスタイムの中央値はどのくらいでしたか？」のような形式で行われます。
これらは φ-分位数として知られており、50パーセンタイルまたは0.5-分位数（中央値とも呼ばれる）を表す `p50` のような省略形で表されることがよくあります。
より一般的に言うと、φ-分位数とは、N 個の観測値の中で φ\*N 番目にランクされる観測値のことです。

## なぜヒストグラムが有用なのか？ {#why-are-histograms-useful}

オブザーバビリティにおけるヒストグラムの一般的なユースケースは、サービスレベル目標（SLO）の定義です。
このような SLO の例としては、「すべてのクエリの99%以上が30ms未満で応答すること」や「すべてのページ読み込みの90%がファーストペイントから100ms以内にインタラクティブになること」などがあります。

以下のグラフでは、ある期間にわたるいくつかのリクエストについて `p50`、`p90`、`p99` のレスポンスタイムがプロットされています。
このデータから、リクエストの50%が約20〜30ms以下で処理され、リクエストの90%が約80ms未満で処理され、リクエストの99%が約90ms未満で処理されていることがわかります。
ユーザーの少なくとも50%が非常に高速なレスポンスタイムを得ていることがすぐにわかりますが、ほぼすべてのユーザーが90ms未満のレスポンスタイムを経験しています。

![p99、p90、p50 の折れ線グラフ](hist-lines.png "p99, p90, and p50 plotted as a line chart with title 'response times.' Time is on the x-axis and response times in milliseconds on the y-axis. p99 response times are around 80 milliseconds. p90 response times are between 60 and 80 milliseconds. p50 response times are between 20 and 30 milliseconds.")

## その他のメトリクスの種類 {#other-metric-types}

すでに他のメトリクスに基づいて SLO を定義している場合はどうでしょうか。
ゲージやカウンターに基づいて SLO を定義することを検討したかもしれません。
このアプローチでも機能しますが、データの分布を理解する前に SLO を定義する必要があり、収集時に単純ではない実装が求められます。
また、柔軟性に欠けます。
SLO をリクエストの90%から99%に変更しようとする場合、コードの変更とリリースを行い、古いデータが古くなるのを待ち、新しいメトリクスが有用なクエリを行うのに十分なデータを収集するのを待つ必要があります。
ヒストグラムは最初から最後までデータを分布としてモデル化するため、クエリを変更するだけで、すでに収集したデータに対する回答を得ることができます。
特に指数ヒストグラムを使えば、非常に低い相対誤差率で、クライアントと分析バックエンドの両方で最小限のリソース消費で、任意の分布クエリを実行できます。

SLO にヒストグラムを使用しないことによる柔軟性の欠如は、SLO が違反された場合の影響を把握する能力にも影響します。
たとえば、あるメトリクスの `p99` を計算するゲージを収集し、それに基づいて SLO を定義しているとしましょう。
SLO が違反されてアラートが発生した場合、それが本当にクエリの1%だけに影響しているのか、10%なのか、50%なのか、どうすればわかるでしょうか。
ヒストグラムを使えば、関心のあるパーセンタイルをクエリすることで、その疑問に答えることができます。

もう1つの選択肢は、関心のある各分位数をゲージとして収集することです。
Prometheus のような一部のシステムでは、サマリーと呼ばれるメトリクスタイプを使用してこれをネイティブにサポートしています。
サマリーは機能しますが、ゲージやカウンターと同じ柔軟性の欠如に悩まされ、収集する分位数を事前に決定する必要があります。
また、集約もできません。
つまり、2つの別々のホストがそれぞれ独自の `p90` を報告している場合、その2つから正確な `p90` を計算することはできません。

## その他のデータソースとメトリクスタイプ {#other-data-sources-and-metric-types}

「既存のログやトレースデータから計算すればよいのに、なぜ別のメトリクスを報告するのか？」と思うかもしれません。
レスポンスタイムのような*一部の*ユースケースではそれが可能であるのは確かですが、*すべての*ユースケースで可能であるとは限りません。
既存のデータから分位数を計算できる場合でも、他の問題に直面する可能性があります。
オブザーバビリティバックエンドが大量の既存データをオンラインでクエリ・分析できるか、または取り込み時にインデックス作成・分析できることを確認する必要があります。
ログやトレースをサンプリングしたり、データを古くして削除するデータ保持ポリシーを採用している場合、それらが派生メトリクスに影響を与えていないこと、または適切に再重み付けされていることを確認する必要があります。
さもなければ、SLO を正確に評価できないリスクがあります。
サンプリング戦略によっては、そもそも不可能な場合もあります。
ヒストグラムを使用することで、これらの微妙な問題が該当する場合にそれらを回避できます。

_この記事のあるバージョンは、著者のブログに[もともと投稿されたもの][originally posted]です。_

[originally posted]: <https://dyladan.me/histograms/2023/05/02/why-histograms/>
