前言
Prometheus 是監控與告警系統的工具集,將數據以時間序列的格式存在 TSDB (Time Series Database) 中,並提供 PromQL 來對資料做查詢。histogram_quantile 為其中一個聚合函式,讓我們能夠透過 histogram 類型的 metric 推算出指定的百分位數所對應的值,應用更靈活。在解讀數據之前,個人認為要先了解數據是如何得到的,因此這篇文章紀錄 histogram_quantile 的演算法原理。
histogram_quantile 原理
Prometheus 是開源專案,所有功能背後的底層實現都能在 Prometheus GitHub 找到,我們所在乎的 histogram_quantile 也不例外。原始碼是最直接理解運作原理的方式,因此直接為相關原始碼作註解,使讀者容易理解運算邏輯
1 | type bucket struct { |
範例
histogram_quantile 通常通常其會搭配 sum 與 rate 來使用,因此常會看到 histogram_quantile(q, sum(rate()) by (le))
這樣的 PromQL 出現。到目前為止,已經明白 histogram_quantile 背後的運作原理,再來就是以範例數據來強化記憶。
情境說明
情境與目標:監控的 Server 有兩個端點,分別為 /user/
與 /system/
,我們要想要知道每 1 分鐘內 90 百分位的 http 處理時間 (不限定端點)。
Metric 定義
用來紀錄 http request 所需處理時間的 metric 的定義如下,其為 histogram 型態
1 | prometheus.NewHistogramVec(prometheus.HistogramOpts{ |
結論
使用 PromQL 如下,即可得到想要的結果
1 | histogram_quantile(0.90, sum(rate(http_request_seconds_bucket[1m])) by (le)) |
以實例說明運作原理
接著,以實例作為輔助來解析這段 PromQL 的含義
數據說明
假設在時間點 t - 1m 時,metrics 的數值如下
1 | http_request_seconds_bucket{handler="/user/",le="0.005"} 5 |
再假設在時間點 t 時,metrics 的數值如下
1 | http_request_seconds_bucket{handler="/user/",le="0.005"} 6 |
計算步驟頗析
首先計算 rate(http_request_seconds_bucket[1m])
,即 t 時刻的 metric 的值減去 t - 1m 的 metric 的值
rate(http_request_seconds_bucket{handler="/user/"}[1m]) |
rate(http_request_seconds_bucket{handler="/system/"}[1m]) |
|
---|---|---|
le=0.005 | 1 | 5 |
le=0.01 | 48 | 106 |
le=0.025 | 344 | 518 |
le=0.05 | 713 | 936 |
le=0.1 | 1147 | 1317 |
le=0.25 | 1607 | 1720 |
le=0.5 | 1790 | 1878 |
le=1 | 1884 | 1961 |
le=2.5 | 2000 | 1987 |
le=5 | 2000 | 2000 |
le=10 | 2000 | 2000 |
le=+Inf | 2000 | 2000 |
sum(rate(http_request_seconds_bucket[1m])) by (le)
則是將兩個 rate
的結果,根據 le
把結果相加起來
sum(rate(http_request_seconds_bucket[1m])) by (le) |
|
---|---|
le=0.005 | 6 |
le=0.01 | 154 |
le=0.025 | 862 |
le=0.05 | 1649 |
le=0.1 | 2464 |
le=0.25 | 3327 |
le=0.5 | 3668 |
le=1 | 3845 |
le=2.5 | 3987 |
le=5 | 4000 |
le=10 | 4000 |
le=+Inf | 4000 |
最後,在 golang 內部會將這些 buckets 轉為 go 的 buckets 物件並呼叫 bucketQuantile
函數計算出 90 百分位對應的值,可以將最後的 histogram_quantile
運算等效成以下 golang 程式碼
1 | // histogram_quantile(0.90, sum(rate(http_request_seconds_bucket[1m])) by (le)) |
舉一反三
這樣的 PromQL 是根據整體的數據來查看 90 百分位數的值
1 | histogram_quantile(0.90, sum(rate(http_request_seconds_bucket[1m])) by (le)) |
但若我們想要查看指定端點的話呢?非常簡單,假設我們只想查看 /user/
90 百分位數的值,只需加上篩選條件 {handler="/user/"}
即可
1 | histogram_quantile(0.90, sum(rate(http_request_seconds_bucket{handler="/user/"}[1m])) by (le)) |