Prometheus之PromQL用法詳解


前言

    Promethues是目前一個比較流行的開源監控項目,被使用也越來越多。我們都知道Prometheus是通過時序數據庫來保存數據的,那么Prometheus采集到數據后,是如何保存在自已的時序數據庫中的呢?通常我們看到Prometheus的數據指標都類似這樣:node_cpu_seconds_total{cpu="0",instance="10.20.9.183:9101",job="node_exporter",mode="system"},可以看到它是通過指標名稱(metrics name)以及對應的一組標簽(labelset)來唯一標識一條時間序列。那么如何對這種數據進行篩選查詢、四則運算、聚合運算,以實現我們想要繪制的指標監控數據,就需要用到下面將要講到的PromeQL了。

1 PromQL介紹

    Prometheus提供了一種稱為PromQL(Prometheus Query Language)的功能性查詢語言,讓用戶可以實時選擇和聚合時間序列數據。在Prometheus默認的瀏覽器中,表達式的結果既可以顯示為圖形,也可以以表格數據的形式顯示,或者由外部系統通過HTTP API使用。
    PromeQL在很多地方都會被用到,在Prometheus UI界面搜索監控指標時會用到,在Alertmanager配置告警時也會用到,在Grafana配置監控展示的時候也會用到。
    下面在講解的過程中,使用到了很多例子,可能部分例子在真實的監控環境中並沒有具體的實際含義,僅僅是為了進行演示,便於理解學習。因為在實際的生產環境中,要得到一些目標監控值,是要綜合多個運算符或者函數來實現的。

2 數據類型

    在Prometheus的表達式語言中,表達式或子表達式的計算結果可以為四種類型之一:
Instant vector - 瞬時數據:一組時間序列,每個時間序列包含一個樣本,都共享相同的時間戳;
Range vector - 區間數據:一組時間序列,其中包含每個時間序列隨時間變化的一系列數據點;
Scalar - 簡單數據:一個簡單的數字浮點值;
String - 字符串值:一個簡單的字符串值,目前未使用。

2.1 Instant vector 瞬時數據

瞬時數據表示的是在當前時刻的數據。
查詢cpu的使用時間

node_cpu_seconds_total

2.2 Range vector 區間數據

區間數據表示的是在某一個時間范圍內的數據,可以分為以下幾種。

2.2.1 Time Durations

Time Durations表示持續時間,計量單位有以下這些:
ms - 毫秒
s - 秒
m - 分
h - 時
d - 天
w - 周
y - 年
查詢cpu 1分鍾內的使用時間
采樣周期是15s,可以看到1分鍾內,每個指標有4個值

node_cpu_seconds_total[1m]

2.2.2 Offset modifier

Offset modifier表示偏移量修飾符,允許更改查詢中單個瞬間和范圍向量的時間偏移量。
查詢cpu使用時間在5分鍾之前的數據

node_cpu_seconds_total offset 5m

2.2.3 @ modifier

@修飾符,后面加上一個unix時間戳,可以查詢該時間點的數據。
注意:這種用法需要prometheus啟動的時候添加參數:--enable-feature=promql-at-modifier,並且以前老版本的prometheus可能不支持這種用法。
查詢2022.01.25 00:00:00 這個時刻cpu的使用時間

node_cpu_seconds_total @ 1643040000

2.3 Scalar 簡單數據

簡單數據沒有時間屬性,每個時間點數值一致。
查詢cpu使用時間,所有標簽的個數

count(node_cpu_seconds_total)

3 條件匹配

PromQL支持各種條件匹配
條件匹配符有:==、!=、=~、!~
= : 選擇與提供的字符串完全相同的數據
!= : 選擇不等於提供的字符串的數據
=~ : 選擇與提供的字符串進行正則表達式匹配的數據
!~ : 選擇與提供的字符串不匹配的數據

3.1 普通匹配

查詢cpu第一個核的使用時間

node_cpu_seconds_total{cpu="0"}

查詢cpu除了第一個核以外的其他核的使用時間

node_cpu_seconds_total{cpu!="0"}

查詢cpu第一個、第二個核的使用時間

node_cpu_seconds_total{cpu=~"0|1"}

查詢cpu除了第一個、第二個核的使用時間

node_cpu_seconds_total{cpu!~"0|1"}

3.2 正則匹配

查詢cpu第一個核,idle、iowait、irq態的使用時間

node_cpu_seconds_total{cpu="0",mode=~"i.*"}

4 運算符

PromQL支持各種運算符

4.1 比較運算符

比較運算符有:==、!=、>、<、>=、<=
比較運算符與數學中和其他語言的含義是一樣的
查詢cpu使用時間為0的標簽

node_cpu_seconds_total == 0

查詢cpu使用時間不為0的標簽

node_cpu_seconds_total != 0

查詢cpu使用時間大於100的標簽

node_cpu_seconds_total > 100

查詢cpu使用時間小於4的標簽

node_cpu_seconds_total < 4

>=、<=的用法與上面類似,這里就不在舉例子了。

4.2 算術運算符

算數運算符有:+、-、*、/、%、^
與數學里面的算數運算符含義一樣,分別為:加、減、乘、除、取余、冪次方
需要注意的是:做算數運算符的兩個指標,必須標簽完全一樣
計算主機cpu使用時間和主機上面虛擬機使用時間的和

node_cpu_seconds_total + node_cpu_guest_seconds_total

計算主機cpu使用時間和主機上面虛擬機使用時間的差

node_cpu_seconds_total - node_cpu_guest_seconds_total

計算2倍cpu使用時間

node_cpu_seconds_total - node_cpu_guest_seconds_total

cpu使用時間除以1000

node_cpu_seconds_total - node_cpu_guest_seconds_total

cpu使用時間的平方

node_cpu_seconds_total - node_cpu_guest_seconds_total

4.3 邏輯運算符

邏輯運算符有:and、or、unless
對應其他語言的與、或、非
查詢cpu的時間大於0並且小於10的標簽

node_cpu_seconds_total > 0 and node_cpu_seconds_total < 10

查詢cpu的時間大於100或者小於1的標簽

node_cpu_seconds_total > 100 or node_cpu_seconds_total < 1

查詢cpu的時間不是小於100的標簽

node_cpu_seconds_total unless node_cpu_seconds_total < 100

4.4 聚合運算符

4.4.1 sum:求和

計算cpu所有核的總使用時間

sum(node_cpu_seconds_total)

4.4.2 count:計數

計算cpu的核數

count(node_cpu_seconds_total{mode="system"})

4.4.3 max:求最大值

查詢第一個cpu左右運行狀態中使用時間最大的那一個狀態

max(node_cpu_seconds_total{cpu="0"})

4.4.4 min:求最小值

查詢第一個cpu左右運行狀態中使用時間最小的那一個狀態

min(node_cpu_seconds_total{cpu="0"})

4.4.5 avg:求平均值

求cpu內核態(system)的平均使用時間

avg(node_cpu_seconds_total{mode="system"})

4.4.6 topk:取前面幾個較大值

查詢cpu內核態(system)的排名前兩個的核

topk(2,node_cpu_seconds_total{mode="system"})

4.4.7 bottomk:取后面幾個較小值

查詢cpu內核態(system)的排名后兩個的核

bottomk(2,node_cpu_seconds_total{mode="system"})

4.5 匹配運算

4.5.1 on:關聯標簽

將兩個指標進行算數運算時,如果兩個指標的標簽不完全相同,可以匹配相同的標簽進行計算
計算cpu每個核系統態和用戶態的總使用時間

node_cpu_seconds_total{mode="system"} + on (instance,cpu) node_cpu_seconds_total{mode="user"}

4.5.2 ignoring:忽略標簽

將兩個指標進行算數運算時,如果兩個指標的標簽不完全相同,可以忽略不一樣的標簽進行計算
忽略運行狀態,計算cpu每個核系統態和用戶態的總使用時間,實現的效果與上面相同

node_cpu_seconds_total{mode="system"} + ignoring (mode) node_cpu_seconds_total{mode="user"}

4.5.3 by:以某一個標簽進行計算

計算每個cpu核的各個狀態的總使用時間

sum(node_cpu_seconds_total) by (cpu) 或者 sum by (cpu) (node_cpu_seconds_total)

計算每個狀態下cpu所有核的總使用時間

sum(node_cpu_seconds_total) by (mode) 或者 sum by (mode) (node_cpu_seconds_total)

4.5.4 without:舍棄某個標簽進行計算

作用與by相反
計算每個cpu核的各個狀態的總使用時間,與上面by的效果相同

sum (node_cpu_seconds_total) without (mode) 或者 sum without (mode) (node_cpu_seconds_total)

5 函數

5.1 速率函數

5.1.1 increase:求增長值

求cpu第一個核,system態的使用時間在過去1分鍾的增加量

increase(node_cpu_seconds_total{cpu="0",mode="system"}[1m])

求cpu第一個核,system態的使用時間在過去1分鍾的每秒平均增速

increase(node_cpu_seconds_total{cpu="0",mode="system"}[1m]) / 60

5.1.2 rate:求每秒平均增長率

與上面的increase求增速效果相同
求cpu第一個核,system態的使用時間在過去1分鍾的每秒平均增速

rate(node_cpu_seconds_total{cpu="0",mode="system"}[1m])

5.1.3 irate:求每秒瞬時增長率

求cpu第一個核,system態的使用時間在過去1分鍾的每秒瞬時增速

irate(node_cpu_seconds_total{cpu="0",mode="system"}[1m])

5.1.4 rate和irate區別

rate會取指定時間范圍內所有樣本數據點,然后計算平均增長速率,可能容易陷入“長尾問題”,無法反應出突發變化,比如機器在一個時間窗口內,可能出現CPU占用100%的情況,但是通過計算在時間窗口內的平均增長率,數據就會被平均,就無法反應出該問題。
irate是通過在指定時間范圍內最后兩個樣本數據來計算區間增長速率,反應出的是瞬時增長率。這種方式可以避免在時間窗口范圍內的“長尾問題”,體現出更好的靈敏度,通過irate函數繪制的圖標能夠更好的反應樣本數據的瞬時變化狀態。
雖然rate和rate都會用於計算某個指標在一定時間間隔內的變化速率,irate適合快速變化的計數器(counter),而rate適合緩慢變化的計數器(counter)。

5.2 取整函數

5.2.1 ceil:向上取整

查看第一個cpu的使用時間,向上取整

ceil(node_cpu_seconds_total{cpu="0"})

5.2.2 floor:向下取整

查看第一個cpu的使用時間,向下取整

floor(node_cpu_seconds_total{cpu="0"})

5.2.3 round:四舍五入

查看第一個cpu的使用時間,四舍五入

round(node_cpu_seconds_total{cpu="0"})

下面是沒有經過處理的
查看cpu的使用時間,可以對比上面幾個

node_cpu_seconds_total{cpu="0"}

5.3 排序函數

5.3.1 sort:排序

查看第一個cpu的使用時間,從小到大排序

sort(node_cpu_seconds_total{cpu="0"})

5.3.2 sort_desc:逆向排序

查看第一個cpu的使用時間,從小到大排序

sort_desc(node_cpu_seconds_total{cpu="0"})

5.4 其他函數

5.4.1 abs:求絕對值

求cpu使用時間的絕對值

abs(node_cpu_seconds_total{cpu="0"})

5.4.2 absent:設置值

當指標存在時不會返回值,當指標不存在時會返回值,切回將值設置為1
node_cpu_seconds_total{cpu="0",mode="system"}本身存在,返回空

absent(node_cpu_seconds_total{cpu="0",mode="system"})

node_cpu_cpu_seconds_total{cpu="0",mode="system"}本身不存在,返回1

absent(node_cpu_cpu_seconds_total{cpu="0",mode="system"})

參考文檔

https://prometheus.io/docs/prometheus/latest/querying/basics/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM