一文搞懂 Prometheus 的直方圖

米開朗基楊發表於2019-08-06

原文連結:一文搞懂 Prometheus 的直方圖

Prometheus 中提供了四種指標型別(參考:Prometheus 的指標型別),其中直方圖(Histogram)和摘要(Summary)是最複雜和難以理解的,這篇文章就是為了幫助大家加深對這 histogram 型別指標的理解。

1. 什麼是 Histogram?

根據上篇文件,Histogram 會在一段時間範圍內對資料進行取樣(通常是請求持續時間或響應大小等),並將其計入可配置的儲存桶(bucket)中。但這句話還是不太好理解,下面通過具體的示例來說明。

假設我們想監控某個應用在一段時間內的響應時間,最後監控到的樣本的響應時間範圍為 0s~10s。現在我們將樣本的值域劃分為不同的區間,即不同的 bucket,每個 bucket 的寬度是 0.2s。那麼第一個 bucket 表示響應時間小於等於 0.2s 的請求數量,第二個 bucket 表示響應時間大於 0.2s 小於等於 0.4s 的請求數量,以此類推。

一文搞懂 Prometheus 的直方圖

Prometheus 的 histogram 是一種累積直方圖,與上面的區間劃分方式是有差別的,它的劃分方式如下:還假設每個 bucket 的寬度是 0.2s,那麼第一個 bucket 表示響應時間小於等於 0.2s 的請求數量,第二個 bucket 表示響應時間小於等於 0.4s 的請求數量,以此類推。也就是說,每一個 bucket 的樣本包含了之前所有 bucket 的樣本,所以叫累積直方圖。

一文搞懂 Prometheus 的直方圖

2. 為什麼是累積直方圖?

上節內容告訴我們,Prometheus 中的 histogram 是累積的,這是很奇怪的,因為通常情況下非累積的直方圖更容易理解。Prometheus 為什麼要這麼做呢?

想象一下,如果 histogram 型別的指標中加入了額外的標籤,或者劃分了更多的 bucket,那麼樣本資料的分析就會變得越來越複雜。如果 histogram 是累積的,在抓取指標時就可以根據需要丟棄某些 bucket,這樣可以在降低 Prometheus 維護成本的同時,還可以粗略計算樣本值的分位數。通過這種方法,使用者不需要修改應用程式碼,便可以動態減少抓取到的樣本數量。

假設某個 histogram 型別指標的樣本資料如下:

一文搞懂 Prometheus 的直方圖

現在我們希望 Prometheus 在抓取指標時丟棄響應時間在 100ms 以下的 bucket,就可以通過下面的 relabel 配置來實現:

一文搞懂 Prometheus 的直方圖

其中,example_latency_seconds_bucket 用來匹配標籤 __name__ 的值,'0.0.*' 用來匹配標籤 le 的值,即 le 的值為 0.0x。然後將匹配到的樣本丟棄。

通過這種方法,你可以丟棄任意的 bucket,但不能丟棄 le="+Inf" 的 bucket,因為 histogram_quantile 函式需要使用這個標籤。

另外 histogram 還提供了 _sum 指標和 _count 指標,即使你丟棄了所有的 bucket,仍然可以通過這兩個指標值來計算請求的平均響應時間。

通過累積直方圖的方式,還可以很輕鬆地計算某個 bucket 的樣本數佔所有樣本數的比例。例如,想知道響應時間小於等於 1s 的請求佔所有請求的比例,可以通過以下公式來計算:

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

3. 分位數計算

Prometheus 通過 histogram_quantile 函式來計算分位數(quantile),而且是一個預估值,並不完全準確,因為這個函式是假定每個區間內的樣本分佈是線性分佈來計算結果值的。預估的準確度取決於 bucket 區間劃分的粒度,粒度越大,準確度越低。以下圖為例:

一文搞懂 Prometheus 的直方圖

假設有 10000 個樣本,第 9501 個樣本落入了第 8 個 bucket。第 8 個 bucket 總共有 368 個樣本,其中第 9501 個樣本在該 bucket 中屬於第 93 個樣本。

根據 Prometheus 原始碼檔案 promql/quantile.go 第 108 行的公式:

return bucketStart + (bucketEnd-bucketStart)*float64(rank/count)

我們可以計算(quantile=0.95)的樣本值為:

一文搞懂 Prometheus 的直方圖

這個值已經很接近精確的分位數值了。關於 histogram_quantile 函式的詳細使用方式,請參考:PromQL 內建函式

4. 總結

本文主要介紹了 histogram 的工作原理以及分位數的計算方法,相信通過本文的拋磚引玉,大家應該對 Prometheus 的 histogram 有了更深一步的瞭解,下篇文章將會為大家呈現 Summary 的工作方式。

5. 參考資料

一文搞懂 Prometheus 的直方圖

相關文章