前言
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/