大家好,我是藍胖子,書接上文,我在prometheus描點原理那一篇文章裡,留了一個思考題:
我們通常會用到histogram_quantile去計算服務介面時間的耗時情況。
histogram_quantile(0.99,rate(server_handle_seconds_bucket{}[1m]))
但是rate函數會將原指標按時間求斜率,這樣會影響原本分位數的計算嗎?
先說下結論,不影響分位數結果的計算。要解釋這個問題,還是要看看分位數統計Histogram的原理。
在解釋統計原理之前,我們先看看Histogram指標指標究竟是如何儲存的,當我們用prometheus 使用者端建立一個Histogram監控資料型別時,其本質上會建立一組指標,如下所示:
注意概念,在prometheus中,如果指標名和標籤完全相同,那麼將會認為他們是同一個指標,將攜帶有時間戳的指標 稱為指標的樣本。prometheus server web控制檯查詢出來的就是樣本。
# TYPE server_handle_seconds histogram
server_handle_seconds_bucket{type="http",le="0.005"} 0
server_handle_seconds_bucket{type="http",le="0.01"} 0
server_handle_seconds_bucket{type="http",le="0.025"} 0
server_handle_seconds_bucket{type="http",le="0.05"} 0
server_handle_seconds_bucket{type="http",le="0.1"} 0
server_handle_seconds_bucket{type="http",le="0.25"} 0
server_handle_seconds_bucket{type="http",le="0.5"} 0
server_handle_seconds_bucket{type="http",le="1"} 0
server_handle_seconds_bucket{type="http",le="2.5"} 0
server_handle_seconds_bucket{type="http",le="5"} 0
server_handle_seconds_bucket{type="http",le="10"} 37092
server_handle_seconds_bucket{type="http",le="+Inf"} 37092
server_handle_seconds_sum{type="http"} 370920
server_handle_seconds_count{type="http"} 37092
le標籤可以認為是Histogram監控資料型別特有的標籤,含義是桶的上邊界, 拿上述指標server_handle_seconds_bucket{type="http",le="10"} 舉例,這個指標的值是37092,表示小於等於10s的請求有37092次。直方圖Histogram每個桶中統計的次數包含了前面的桶的次數。
histogram_quantile在計算分位數時,就是判斷指標樣本中是否攜帶le標籤,是的話才會納入分位數的計算中。並且histogram_quantile函數是拿一組瞬時向量進行計算的,計算後得到一個分位數。
注意下概念,在prometheus中,向量vector是指 單個時間點的指標樣本,矩陣matrix是一組時間點的樣本。無論是vector還是matrix,他們都可以是多個指標,不過區別在於指標的樣本是單個時間點的,還是一組時間節點的。
拿上述指標舉例,histogram_quantile 計算時就是拿指標名為server_handle_seconds_bucket的指標集合 某個時間節點的指標值進行計算的。指標集合包含下面幾個指標
## 指標名和標籤 指標值
server_handle_seconds_bucket{type="http",le="0.005"} 0
server_handle_seconds_bucket{type="http",le="0.01"} 0
server_handle_seconds_bucket{type="http",le="0.025"} 0
server_handle_seconds_bucket{type="http",le="0.05"} 0
server_handle_seconds_bucket{type="http",le="0.1"} 0
server_handle_seconds_bucket{type="http",le="0.25"} 0
server_handle_seconds_bucket{type="http",le="0.5"} 0
server_handle_seconds_bucket{type="http",le="1"} 0
server_handle_seconds_bucket{type="http",le="2.5"} 0
server_handle_seconds_bucket{type="http",le="5"} 0
server_handle_seconds_bucket{type="http",le="10"} 37092
server_handle_seconds_bucket{type="http",le="+Inf"} 37092
所以我們在計算時為什麼要將server_handle_seconds_bucket{}[1m] 用rate函數進行計算,因為單獨的server_handle_seconds_bucket{}[1m] 返回的資料型別是matrix型別,是一組時間節點的樣本,即某個 桶型別的指標有多個樣本值,而 histogram_quantile 只要求一個桶型別的指標(攜帶le的指標)只有一個樣本值。所以通過rate函數將一個矩陣型別的資料變成了向量型別
搞懂了為什麼要用rate函數,再來看看為什麼rate函數改變了桶的大小後不會對分位數計算邏輯產生影響。
拿文章開頭的計算分位數的表示式舉例
histogram_quantile(0.99,rate(server_handle_seconds_bucket{}[1m]))
我們需要計算指標名為server_handle_seconds_bucket 在過去1分鐘內的資料的百分之99分位數。
histogram_quantile計算步驟如下:
1, 首先會拿最後一個桶中(因為最後一個桶包含了所有樣本的個數)的統計的次數去乘以分位數,看下第99分位是所有樣本資料中的第幾個,假設用rank變數儲存這個結果。
2,拿上一步的計算結果rank值挨個桶比較統計次數,找到第一個桶的次數大於等於rank值的桶。這一步就計算出了99分位的樣本是在哪個桶裡。
3,最後通過下面的計算估算99分位數是多少
bucketStart + (bucketEnd-bucketStart)*(rank/count)
bucketEnd 和bucketStart是桶的上下邊界值,估算分位數是多少時,是預設在這個桶內,資料是線性均勻分佈的,所以拿(bucketEnd-bucketStart)*(rank/count) 估算出99分為的數在這個桶內的偏移量。
所以,你可以看到分位數的計算雖然用到了count值,但是是拿count值和rank值相除得到一個比例,rate函數雖然將桶指標的count值變小了,但由於計算時,我僅僅是求一個比例值,所以對分位數的結果運算並不影響。