詳解 Prometheus range query 中的 step 參數¶
原文: 详解Prometheus range query中的step参数
詳細解釋Prometheus range query中的step參數的作用。
區間查詢參數¶
Prometheus 有兩種 query:instant query、range query。本文要講的就是 range query 中的 step 參數。
range query 是非常常見的一種 query,看看它有哪些參數:
query=<string>PromQL表達式。start=<rfc3339 | unix_timestamp>時間範圍的開始。end=<rfc3339 | unix_timestamp>時間範圍的結束。step=<duration | float>查詢解析度(query resolution)。timeout=<duration>執行超時。這個參數是 optional。
在 Prometheus expression browser 裡看到的是這樣的:
注意到上圖中的 Res 框 裡沒有給值,沒有給的話 Prometheus 會自動給一個值,這個值在圖示右上角可以看到。
Step 參數對於查詢結果的影響¶
Prometheues 在對 PromQL 表達式求值的邏輯是這樣的(詳見這個issue裡的回答):
- 對於 [start, end] 時間區間,從 start 開始,以 step 為長度,把時間區間分成若干段
- 對每個段進行求值
舉例:start=10,end=20,step=2,那麼就會有ts=10,ts=12,ts=14,ts=16,ts=18,ts=206段,然後為這 6 個段進行求值。求值方式視乎表達式中 Time series selector 的類型而定。
PromQL 有兩種 Time series selector:instant vector selector 和 range vector selector。下面將分別講解:
瞬時向量選擇器¶
下面的就是 Instant vector selector 的範本,x 是 metric 的名字。
Prometheus 在對每段 Instant vector selector 求值的邏輯是這樣的:
- 從該段的 timestamp(含)往前找,取第一個找到的 data point 的值。如果有一個
data point的timestamp==該段的timestamp,則直接使用該 data point。 - 如果該段 timestamp 往前的 5 分鐘範圍內沒有找到任何 data point,則該段無值。
下面這張圖解釋了上面邏輯:
圖中的綠點是 Prometheus 實際存儲的數據,按照時間軸從左到右排列。藍點是根據 step 參數的求值結果。
當 data point 間隔比 step 更大的時候會發生下圖這種情況:
可以看到有兩個時間區段的求值結果來自於同一個 data point。
區間向量選擇器¶
下面的就是 Range vector selector,x 是 metric 的名字,方括号里的是 range duration。
range vector select 返回的是當前 timestamp 之前的 range duration 內的所有 data point。 range vector 是不能直接用做繪圖的,你得用某些 function 把 range vector 轉換成 instant vector才行,比如 rate()。
下圖解釋了是如何對 Range vector selector 進行分時間區段求值的:
Step 和 Rate duration 參數¶
step 和 range duration 是獨立的兩個參數,在某些情況下兩者的值存在某種限制條件,這裡例舉 rate() 來說明。 rate() 的作用是獲得一個 range-vector 的每秒平均增長率。
如果 step=10m 而 range duration=5m,那麼 rate 在計算的時候會丟失一半的數據,兩個時間分段之間的 data point 有一半沒有被納入計算。前面那張圖就存在數據丟失的情況,有一個 data point 被漏掉了。
因此在使用 rate() 時,range duration 得大於等於 step。
而如果是 irate(),這個限制則是 range duration 不得大於 step(詳見 Brian Brazil的Presentation)。
Grafana 中的 step 參數¶
在 Grafana 中並沒有直接提供 step 參數,而是這兩個參數:min step 和 resolution(文檔在這裡)。 min step 故名思義設定的是 step 的最小值,那麼 resolution 是什麼呢?
大家都知道 Grafana 都是用來畫圖表的,比如下面這張圖Y軸是 值,X軸是 時間線,因此在X軸方向的每個像素都代表了一個 timestamp。
resolution 就是用來根據像素來計算 step 的一個參數。下面用 6 個像素以及它們的 timestamp 來說明:
resolution=1/1時,那麼step就是相鄰像素所代表的timestamp的差,即 5;resolution=1/2時,那麼step就是相隔 1 個像素的兩個像素的timestamp的差,即 10;resolution=1/3時,那麼step就是相隔 2 個像素的兩個像素的timestamp的差,即 15;-- 以此類推
而每個像素所代表的 timestamp 受兩個因素影響:
- 查詢所定義的時間範圍
- Graph的寬度(單位:像素)
所以在 Grafana 發起的查詢中 step 參數是動態的。其實這也是很合理的,因為只有這樣才能夠在 Graph 寬度小的時候繪圖更粗糙(即 step 更大),Graph 寬度大的時候繪圖更精細(即 step 更小,但是不能小於 min step)。實際發起的請求的 step 參數你可以在 Graph 的 Query Inspector 裡看到:
但是我們之前不說過了 rate() 的 range duration 不能小於 step 嗎?那麼把 range duration 給固定值的化就不太好了,怎麼辦呢?你可以使用 Grafana 提供的內置變量$__interval,它代表的是 Grafana 計算出來的 step 的值。比如這樣就能夠將 range duration 和 step 保持一致了(更多內置變量可以見這裡):
所以,你想自己實驗一把¶
如果你想自己動手實驗,但是又苦於無法製造乾淨的假數據,那麼可以參考這篇文章推薦的方法。





