prometheus 描點原理

大家好,我是藍胖子,關於 prometheus 的入門教程有很多,拿我之前學 prometheus 的經歷來講,看了很多教程,還是會對 prometheus 的描點以及背後的統計原理感到迷惑,所以今天我們就來分析下這部分,來揭開其神祕的面紗。

我們先來看看 prometheus 裏的數據模型是怎麼樣的,只有知道了數據結構,才能理解對後續這些數據如何描點,如何計算出相應指標值。

數據模型

prometheus 中存的是時序數據,時序數據有個特點是每條數據都有一個時間戳,並且時序數據都有一個 metric_name(指標名),和一系列的 label,以及當前指標的值 value。當用 prometheus web 控制檯查詢出來的就是一條條時序數據,如下圖所示:

時序數據描述一個指標的表達式可以歸納爲:

metric_name{label_name1=label_val1,label_name2=label_val2,....}

表達式開頭是指標名,{} 裏的就是指標的標籤。

「在 prometheus 中,如果指標名和標籤完全相同,那麼將會認爲他們是同一個指標,將一個指標不同時間戳的時序數據稱爲指標的樣本。」

這裏要特別明確一點,用過 prometheus 客戶端的同學都知道 prometheus 有四大指標類型 Counter,Guage,Histogram,Summary,但無論是哪種指標類型在 prometheus 服務端這邊都是按照上述的指標格式進行存儲的,prometheus server 在存儲時並不會去存特定某個指標是什麼指標類型。

理解了 prometheus server 存儲數據的類型,我們再來看看對 prometheus server 進行查詢時的數據返回類型。

prometheus server 提供了兩個 api 對外提供查詢,分別是 「query」  和 「query_range」  ,在 prometheus 中 用 「vector」 類型表示單個時間點的指標數據,用 「matrix」 表示一組時間點的指標數據。所以 query_range api 只能返回 「matrix」 類型的數據。我們用 prometheus web 控制檯演示下。

首先來看下在 table 列進行查詢時涉及的查詢,在 table 列進行查詢會調用到 「query」 的 api,其返回結果既可以是 「matrix」 類型,也可以是 「vector」 類型。

「如上圖所示,查詢返回的是 vector 類型的數據」  ,  我們在 table 這一欄輸入 PromQl 查詢語句,默認是查出當前時間最新的指標,可以看到返回的 result 是一個數組,因爲匹配查詢語句的不止一個指標,接着返回了指標的時間戳以及對應的值 val。

在 table 這一列除了查詢某個指標的瞬時值,還可以 「查某段時間內的值,對應的 prometheus server api 的返回類型就將是 matrix 類型了」 , 如下圖所示,我們可以修改 PromQl 語句讓其查 1m 內的數據:

如上圖所示,將查詢語句改爲 「go_memstats_other_sys_bytes{}[1m]」  後返回的就是 matrix 類型的數據了,它表示一組時間點的數據。

其實看到這裏,你應該能想到,prometheus 繪圖就是根據 「matrix 類型的數據進行描點繪圖的」

描點原理

緊接着,我們就來看下 prometheus 的描點繪圖原理。

首先要明確一點,繪圖的原理本質上就是在一個個時間片段裏進行描點,然後再將各個點連起來就形成了隨時間變化的監控圖 Graph。所以在描點繪圖時,用到的數據查詢結果僅僅只能是 matrix 類型,因爲只有它才能表示一個指標一組時間點的樣本值。

我們再回顧下 matrix 數據格式是怎樣的,

matrix 數據格式的返回,每個指標都會攜帶一組時間點的樣本,到時候描點時就是根據這些樣本點的時間點爲橫座標,樣本的值爲縱座標進行繪圖的。

接着,我們來看下繪圖用到的查詢數據 api, 和在 table 欄進行查詢不同,在繪圖界面查詢數據用到的 api 是 「query_range」 ,query_range 返回的數據格式是 「matrix」 類型的數據

注意下 query_range 的參數,已經和 query 不同了,因爲 query 畢竟只查基於某個時間點的數據,而 query_range 是查某段時間的數據,所以 query_range 有個開始時間 start 和結束時間 end,除此以外,它還有個參數 step,這個參數是表示將 start 和 end 之間的時間段按 step 步長分割爲更小的時間段,然後在 「每個小的時間段內將會產生一個描點」 。最後就是將指標的描點全部連接起來就是一個曲線了。

描點是如何計算出來的

知道了在每個小的時間段內,prometheus 會產生一個描點,我們還需要知道描點究竟是如何計算出來的。

拿截圖的表達式 「rate(go_memstats_other_sys_bytes[1m])」 舉例,假設時間區間 [start,end] 被 step 分成了 3 小段。

如上圖,其中每段的開始時間戳分別是 A1,A2,A3,按 step 進行累加,這 3 個小的時間段將會產生 3 個描點,每個描點計算規則如下:

val=rate函數(當前時間段與當前時間段減去1m這段時間內的所有樣本)

每個描點,都會執行一次 rate 函數得到描點的 value 值,描點的時間戳則是每個小的時間段開始的時間,而計算的樣本則是 每個小的時間段開始時間到 之前的 1m 的時間範圍內篩選出來的。

histogram_quantile  表達式如何描點的?

上面的描點例子比較簡單,我們來看一個複雜點的,這個也是 Histogram 指標類型統計的原理。

如下,我們通常會用到 histogram_quantile 去計算服務接口時間的耗時情況。

histogram_quantile(0.99,rate(server_handle_seconds_bucket{}[1m]))

它描點的邏輯依然逃不開 將一個大的時間段分爲小的時間段,並且每個小的時間段產生描點。也就是說,每個小的時間段也都會執行一次 histogram_quantile 函數得到描點值,但 histogram_quantile 的樣本值從哪裏得來呢?

是在小的時間段內通過 rate 函數計算得到的,rate 函數的樣本來源也和剛纔講的一樣,是當前時間段與當前時間段減去 1m 這段時間內的所有樣本。

思考題

這樣的確得到了 3 個描點,能繪製出曲線來,但最開始我在看到這個表達式還是很疑惑的,因爲它將之前的每個直方圖的指標都進行了 rate 計算,這樣在用 histogram_quantile 計算最終分位數的時候不會導致結果變化嗎?這就涉及到了 histogram_quantile 計算分爲數的邏輯,有空我會在下篇文章繼續分析。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s?__biz=MzU3NjY5MjY2Ng==&mid=2247487193&idx=1&sn=2c49057727f2e4ed53acf0dc437eae3d&scene=21#wechat_redirect