Prometheus學習系列(七)之Prometheus PromQL說明

前言

本文來自Prometheus官網手冊123 和 Prometheus簡介123
web

PromQL操做符

1、二元操做符

Prometheus的查詢語言支持基本的邏輯運算和算術運算。對於兩個瞬時向量, 匹配行爲能夠被改變。正則表達式

1.1 算術二元運算符

在Prometheus支持下面的二元算術操做符:api

  • + 加法
  • - 減法
  • * 乘法
  • / 除法
  • %
  • ^ 冪等

二元運算操做符定義在scalar/scalar(標量/標量)vector/scalar(向量/標量)、和vector/vector(向量/向量)之間。瀏覽器

  • 在兩個標量之間:評估另外一個標量,這是運算符應用於兩個標量操做數的結果。
  • 在瞬時向量和標量之間:將運算符應用於向量中的每一個數據樣本的值。 若是時間序列即時向量乘以2,則結果是另外一個向量,其中原始向量的每一個樣本值乘以2。
  • 在兩個瞬時向量之間:應用於左側向量中的每一個條目及其右側向量中的匹配元素。 結果將傳播到結果向量中。 右側向量中(沒有匹配條目)不是結果的一部分。

1.2 比較二元操做符

在Prometheus系統中,比較二元操做符有:app

  • == 等於
  • != 不等於
  • > 大於
  • < 小於
  • >= 大於等於
  • <= 小於等於

比較二元操做符定義在scalar/scalar(標量/標量)vector/scalar(向量/標量),和vector/vector(向量/向量)。默認狀況下過濾。 能夠經過在運算符以後提供bool來修改它們的行爲,這將爲值返回01而不是過濾。less

  • 在兩個標量之間:必須提供bool修飾符,而且這些運算符會產生另外一個標量,即0(假)或1(真),具體取決於比較結果。
  • 在瞬時向量和標量之間:將這些運算符應用於向量中的每一個數據樣本的值,而且從結果向量中刪除比較結果爲假的向量元素。 若是提供了bool修飾符,則將被刪除的向量元素的值爲0,而將保留的向量元素的值爲1。
  • 在兩個瞬時向量之間:這些運算符默認表現爲過濾器,應用於匹配條目。 表達式不正確或在表達式的另外一側找不到匹配項的向量元素將從結果中刪除,而其餘元素將傳播到具備其原始(左側)度量標準名稱的結果向量中 標籤值。 若是提供了bool修飾符,則已經刪除的向量元素的值爲0,而保留的向量元素的值爲1,左側標籤值爲1

 如:ide

3 > 2
# 報錯 "comparisons between scalars must use BOOL modifier"
 
3 > bool 2 
# 返回 scalar 1
 
1 > bool 2 

1.3 邏輯/集合二元操做符

邏輯/集合二元操做符只能做用在即時向量, 包括:函數

  • and 交集
  • or 並集
  • unless 補集

vector1 and vector2: 獲得一個由vector1元素組成的向量,其中vector2中的元素具備徹底匹配的標籤集,其餘元素被刪除。post

vector1 or vector2:獲得包含vector1的全部原始元素(標籤集+值)的向量以及vector2vector1中沒有匹配標籤集的全部元素。ui

vector1 unless vector2:獲得一個由vector1元素組成的向量,其中vector2中沒有元素,具備徹底匹配的標籤集。 兩個向量中的全部匹配元素都被刪除。

2、向量匹配

向量之間的操做嘗試在左側的每一個條目的右側向量中找到匹配元素。 匹配行爲有兩種基本類型:一對一和多對一/一對多。

一對一從操做的每一側找到一對惟一條目。 在默認狀況下,這是格式爲vector1<operator>vector2以後的操做。 若是兩個條目具備徹底相同的標籤集和相應的值,則它們匹配。 忽略關鍵字容許在匹配時忽略某些標籤,而on關鍵字容許將所考慮的標籤集減小到提供的列表:
[vector expr] [bin-op] ignoring([label list]) [vector expr]

[vector expr] [bin-op] on([lable list]) [vector expr]

例如樣本數據:

 method_code:http_errors:rate5m{method="get", code="500"} 24
 method_code:http_errors:rate5m{method="get", code="404"} 30
 method_code:http_errors:rate5m{method="put", code="501"} 3
 method_code:http_errors:rate5m{method="post", code="404"} 21

 method:http_requests:rate5m{method="get"} 600
 method:http_requests:rate5m{method="delete"} 34
 method:http_requests:rate5m{method="post"} 120

查詢例子:

method_code:http_errors:rate5m{code="500"} / ignoring(code) method:http_requests:rate5m
這將返回一個結果向量,其中包含每一個方法的狀態代碼爲500的HTTP請求部分,在過去的5分鐘內進行測量。 沒有ignoring(code)就沒有匹配,由於度量標準不共享同一組標籤。 方法putdel的條目沒有匹配,而且不會顯示在結果中:
{method="get"} 0.04 // 24 / 600
{method="post"} 0.05 // 6 / 120

2.2 多對一和一對多向量匹配

多對一和一對多匹配指的是「一」側的每一個向量元素能夠與「多」側的多個元素匹配的狀況。 必須使用group_leftgroup_right修飾符明確請求,其中left/right肯定哪一個向量具備更高的基數。

<vector expr> <bin-op> ignoring(<label list>) group_left(<label list>) <vector expr>

<vector expr> <bin-op> ignoring(<label list>) group_right(<label list>) <vector expr>

<vector expr> <bin-op> on(<label list>) group_left(<label list>) <vector expr>

<vector expr> <bin-op> on(<label list>) group_right(<label list>) <vector expr>

隨組修飾符提供的標籤列表包含來自「一」側的其餘標籤,以包含在結果度量標準中。 對於標籤,只能出如今其中一個列表中。 每次結果向量的序列必須是惟一可識別的。

分組修飾符只能用於比較和算術。 默認狀況下,操做as和除非和或操做與右向量中的全部可能條目匹配。示例查詢:

method_code:http_errors:rate5m / ignoring(code) group_left 
method:http_requests:rate5m

在這種狀況下,左向量每一個method標籤值包含多個條目。 所以,咱們使用group_left代表這一點。 右側的元素如今與多個元素匹配,左側具備相同的method標籤:

{method="get", code="500"} 0.04 // 24 /600
{method="get", code="404"} 0.05 // 30 /600

{method="post", code="500"} 0.05 // 6 /600

{method="post", code="404"} 0.175 // 21 /600

多對一和一對多匹配是高級用例,應該仔細考慮。 一般正確使用忽略ignoring(<labels>)可提供所需的結果。

3、聚合操做符

Prometheus支持如下內置聚合運算符,這些運算符可用於聚合單個即時向量的元素,從而生成具備聚合值的較少元素的新向量:

  • sum (在維度上求和)
  • max (在維度上求最大值)
  • min (在維度上求最小值)
  • avg (在維度上求平均值)
  • stddev (求標準差)
  • stdvar (求方差)
  • count (統計向量元素的個數)
  • count_values (統計相同數據值的元素數量)
  • bottomk (樣本值第k個最小值)
  • topk (樣本值第k個最大值)
  • quantile (統計分位數)

這些運算符能夠用於聚合全部標籤維度,也能夠經過包含withoutby子句來保留不一樣的維度。

<aggr-op>([parameter,] <vector expr>) [without | by (<label list>)] [keep_common]

parameter僅用於count_valuesquantiletopkbottomk。不從結果向量中刪除列出的標籤,而全部其餘標籤都保留輸出。 by相反並刪除未在by子句中列出的標籤,即便它們的標籤值在向量的全部元素之間是相同的。

count_values輸出每一個惟同樣本值的一個時間序列。每一個系列都有一個額外的標籤。該標籤的名稱由聚合參數給出,標籤值是惟一的樣本值。每一個時間序列的值是樣本值存在的次數。

topkbottomk與其餘聚合器的不一樣之處在於,輸入樣本的子集(包括原始標籤)在結果向量中返回。 bywithout僅用於存儲輸入向量。例:

若是度量標準http_requests_total具備按應用程序,實例和組標籤扇出的時間序列,咱們能夠經過如下方式計算每一個應用程序和組在全部實例上看到的HTTP請求總數:

sum(http_requests_total) without (instance)

等價於:

sum(http_requests_total)

要計算運行每一個構建版本的二進制文件的數量,咱們能夠編寫:

count_values("version", build_version)

要在全部實例中獲取5個最大的HTTP請求計數,咱們能夠編寫:

topk(5, http_requests_total)

4、二元運算符優先級

如下列表顯示了Prometheus中二進制運算符的優先級,從最高到最低。

  • ^
  • *, /, %
  • +, -
  • ==, !=, <=, <, >=, >
  • and, unless
  • or

具備相同優先級的運算符是左關聯的。 例如,2 * 3%2至關於(2 * 3)%2。可是^是右關聯的,所以2 ^ 3 ^ 2至關於2 ^(3 ^ 2)

PromQL函數

一些函數有默認的參數,例如:year(v=vector(time()) instant-vector)。意思是有一個參數v是一個瞬時向量,若是沒有提供,它將默認爲表達式vector(time())的值。

1、abs()

abs(v instant-vector)返回輸入向量,全部樣本值都轉換爲其絕對值

2、absent()

absent(v instant-vector)若是傳遞給它的向量具備任何元素,則返回空向量;若是傳遞給它的向量沒有元素,則返回值爲1的1元素向量。這對於在給定度量標準名稱和標籤組合不存在時間序列時發出警報很是有用。

absent(nonexistent{job="myjob"})  
# => {job="myjob"}
absent(nonexistent{job="myjob", instance=~".*"}) 
# => {job="myjob"}
absent(sum(nonexistent{job="myjob"})) 
# => {}

在第二個例子中,absent()試圖從輸入向量中導出1元素輸出向量的標籤。

3、ceil()

ceil(v instant-vector)v中全部元素的樣本值舍入到最接近的整數

4、changes()

對於每一個輸入時間序列,changes(v range-vector)將其值在提供的時間範圍內變化的次數做爲即時向量返回。

5、clamp_max()

clamp_max(v instant-vector, max scalar) 將v中全部元素的樣本值設爲最大。

6、clamp_min()

clamp_min(v instant-vector, min scalar)將v中全部元素的樣本值設爲最小。

7、day_of_month()

day_of_month(v=vector(time()) instant-vector)返回UTC中每一個給定時間的月中的某天。 返回值爲1到31。

8、day_of_week()

day_of_week(v=vector(time()) instant-vector)返回UTC中每一個給定時間的星期幾。 返回值爲0到6,其中0表示星期日等。

9、days_in_month()

days_in_month(v=vector(time()) instant-vector)返回UTC中每一個給定時間的月中天數。 返回值爲28到31。

10、delta()

delta(v range-vector)計算範圍向量v中每一個時間系列元素的第一個和最後一個值之間的差值,返回具備給定增量和等效標籤的即時向量。 如下示例表達式返回如今和2小時以前CPU溫度的差別:

delta(cpu_temp_celsius{host="zeus"}[2h])

delta應僅用於gauges

11、deriv()

deriv(v range-vector)函數,計算一個範圍向量v中各個時間序列二階導數,使用簡單線性迴歸
deriv應僅用於gauges。

12、exp()

exp(v instant-vector)計算v中全部元素的指數函數:

  • Exp(+inf) = +Inf
  • Exp(NaN) = NaN

十3、floor()

floor(v instant-vector)v中全部元素的樣本值舍入爲最接近的整數。

十4、histogram_quantile()

histogram_quatile(φ float, b instant-vector) 計算b向量的φ-直方圖 (0 ≤ φ ≤ 1) 。(有關φ-分位數的詳細解釋和直方圖度量類型的使用,請參見直方圖和摘要。)b中的樣本是每一個桶中的觀察計數。 每一個樣本必須具備標籤le,其中標籤值表示桶的包含上限。 (沒有這種標籤的樣本會被忽略。)直方圖度量標準類型自動提供帶有_bucket後綴和相應標籤的時間序列。使用rate()函數指定分位數計算的時間窗口。

示例:直方圖度量標準稱爲http_request_duration_seconds。 要計算過去10m內請求持續時間的第90個百分位數,請使用如下表達式:

histogram_quantile(0.9, rate(http_request_duration_seconds_bucket[10m]))
http_request_duration_seconds中爲每一個標籤組合計算分位數。 要聚合,請在rate()函數週圍使用sum()聚合器。 因爲histogram_quantile()須要le標籤,所以必須將其包含在by子句中。 如下表達式按做業聚合第90個百分點:
histogram_quantile(0.9, sum(rate(http_request_duration_seconds_bucket[10m])) by (job, le))

要聚合全部內容,請僅指定le標籤:

histogram_quantile(0.9, sum(rate(http_request_duration_seconds_bucket[10m])) by (le))

histogram_quantile()函數經過假設桶內的線性分佈來插值分位數值。 最高桶必須具備+Inf的上限。 (不然,返回NaN。)若是分位數位於最高桶中,則返回第二個最高桶的上限。 若是該桶的上限大於0,則假設最低桶的下限爲0.在這種狀況下,在該桶內應用一般的線性插值。 不然,對於位於最低桶中的分位數,返回最低桶的上限。

若是b包含少於兩個桶,則返回NaN。 對於φ<0,返回-Inf。 對於φ> 1,返回+Inf

十5、holt_winters()

holt_winters(v range-vector, sf scalar, tf scalar)根據v中的範圍產生時間序列的平滑值。平滑因子sf越低,對舊數據的重要性越高。 趨勢因子tf越高,則考慮的數據趨勢越多。 sftf都必須介於0和1之間。

holt_winters只能用於gauges。

十6、hour()

hour(v=vector(time()) instant-vector)返回UTC中每一個給定時間的一天中的小時。 返回值爲0到23。

十7、idelta()

idelta(v range-vector)計算範圍向量v中最後兩個樣本之間的差別,返回具備給定增量和等效標籤的即時向量。

idelta只能用於gauges。

十8、increase()

increase(v range-vector)計算範圍向量中時間序列的增量。 單調性中斷(例如因爲目標重啓而致使的計數器重置)會自動調整。 增長外推以覆蓋範圍向量選擇器中指定的全時間範圍,所以即便計數器僅以整數增量增長,也能夠得到非整數結果。

如下示例表達式返回範圍向量中每一個時間系列在過去5分鐘內測量的HTTP請求數

increase(http_requests_total{job="api-server"}[5m])

increase只能與counter一塊兒使用。 它是rate(v)以指定時間範圍窗口下的秒數,應該主要用於人類可讀性。 在記錄規則中使用rate,以便每秒一致地跟蹤增加率。

十9、irate

irate(v range-vector)計算範圍向量中時間序列的每秒即時增加率。 這基於最後兩個數據點。 單調性中斷(例如因爲目標重啓而致使的計數器重置)會自動調整。

如下示例表達式返回範圍向量中每一個時間序列的兩個最新數據點的最多5分鐘的HTTP請求的每秒速率:

irate(http_requests_total{job="api-server"}[5m])

只應在繪製易失性快速移動計數器時使用irate。 警報和緩慢移動計數器的使用率,由於速率的簡短更改能夠重置FOR子句,而且難以閱讀徹底由稀有峯值組成的圖形。

注意,當將irate()與聚合運算符(例如sum())或隨時間聚合的函數(任何以_over_time結尾的函數)組合時,請始終首先採用irate(),而後進行聚合。 不然,當目標從新啓動時,irate()沒法檢測計數器重置。

二10、label_join()

對於v中的每一個時間序列,label_join(v instant-vector, dst_label string, separator string, src_label_1 string, src_label_2 string, ...)使用separator鏈接全部src_labels的全部值,並返回包含鏈接的標籤dst_label的時間序列 值。 此函數中能夠有任意數量的src_labels

此示例將返回一個向量,每一個時間序列都有一個foo標籤,其中添加了值a,b,c

label_join(up{job="api-server",src1="a",src2="b",src3="c"}, "foo", ",", "src1", "src2", "src3")

二11、label_replace()

對於v中的每一個時間序列,label_replace(v instant-vector, dst_label string, replacement string, src_label string, regex string) 將正則表達式正則表達式與標籤src_label相匹配。 若是匹配,則返回時間序列,標籤dst_label替換爲替換擴展。 $1替換爲第一個匹配的子組,$2替換爲第二個等。若是正則表達式不匹配,則返回時間序列不變。

此示例將返回一個向量,每一個時間序列都有一個foo標籤,其值爲a

label_replace(up{job="api-server",service="a:c"}, "foo", "$1", "service", "(.):.")

二12、ln()

ln(v instance-vector)計算v中全部元素的天然對數。特殊狀況是:

ln(+Inf) = +Inf
ln(0) = -Inf
ln(x<0) = NaN
ln(NaN) = NaN

二十3、log2()

log2(v instant-vector)計算v中全部元素的二進制對數。特殊狀況等同於ln中的特殊狀況。

二十4、log10()

log10(v instant-vector)計算v中全部元素的10進制對數。特殊狀況等同於ln中的特殊狀況。

二十5、minute()

minute(v=vector(time()) instant-vector)以UTC爲單位返回每一個給定時間的分鐘。 返回值爲0到59。

二十6、month()

month(v=vector(time()) instant-vector)返回UTC中每一個給定時間的一年中的月份。 返回值爲1到12,其中1表示1月等。

二十7、predict_linear()

predict_linear(v range-vector, t scalar)根據範圍向量v使用線性迴歸預測從如今起t秒的時間序列值。

predict_linear只能與gauges一塊兒使用。

二十8、rate()

rate(v range-vector)計算範圍向量中時間序列的每秒平均增加率。 單調性中斷(例如因爲目標重啓而致使的計數器重置)會自動調整。 此外,計算推斷到時間範圍的末端,容許錯過刮擦或刮擦循環與範圍的時間段的不完美對齊。

如下示例表達式返回範圍向量中每一個時間系列在過去5分鐘內測量的每秒HTTP請求率:

rate(http_requests_total{job="api-server"}[5m])

rate應僅用於計數器。 它最適用於警報和緩慢移動計數器的圖形。

注意,當將rate()與聚合運算符(例如sum())或隨時間聚合的函數(任何以_over_time結尾的函數)組合時,始終首先採用rate(),而後聚合。 不然,當目標從新啓動時,rate()沒法檢測計數器重置。

二十9、resets()

對於每一個時序數據,resets()在所提供的時間範圍內返回計數器重置次數做爲即時向量。 兩個連續樣本之間的值的任何減小都被解釋爲計數器重置。

resets()只能與counter一塊兒使用。

三10、round()

round(v instant-vector, to_nearest 1= scalar)v中全部元素的樣本值舍入爲最接近的整數。 經過四捨五入解決關係。 可選的to_nearest參數容許指定樣本值應舍入的最近倍數。 這個倍數也多是一個分數。

三11、scalar()

給定單元素輸入向量,scalar(v instant-vector)將該單個元素的樣本值做爲標量返回。 若是輸入向量不具備剛好一個元素,則scalar將返回NaN

三12、sort()

sort(v instant-vector)返回按其樣本值排序的向量元素,按升序排列。

三十3、sort_desc()

sort(v instant-vectorsort相同,但按降序排序。

三十4、sqrt()

sqrt(v instant-vector)計算v中全部元素的平方根。

三十5、time()

time()返回自1970年1月1日UTC以來的秒數。 請注意,這實際上並不返回當前時間,而是返回計算表達式的時間。

三十6、timestamp()

timestamp(v instant-vector)返回給定向量的每一個樣本的時間戳,做爲自1970年1月1日UTC以來的秒數。

此功能已添加到Prometheus 2.0中

三十7、vector()

vector(s scalar)將標量s做爲沒有標籤的向量返回。

三十8、year()

year(v=vector(time()) instant-vector)以UTC格式返回每一個給定時間的年份。

三十9、<aggregation>_over_time()

如下函數容許聚合給定範圍向量的每一個系列隨時間的變化並返回具備每系列聚合結果的即時向量:

  • avg_over_time(range-vector): 範圍向量內每一個度量指標的平均值。
  • min_over_time(range-vector): 範圍向量內每一個度量指標的最小值。
  • max_over_time(range-vector): 範圍向量內每一個度量指標的最大值。
  • sum_over_time(range-vector): 範圍向量內每一個度量指標的求和值。
  • count_over_time(range-vector): 範圍向量內每一個度量指標的樣本數據個數。
  • quantile_over_time(scalar, range-vector): 範圍向量內每一個度量指標的樣本數據值分位數,φ-quantile (0 ≤ φ ≤ 1)
  • stddev_over_time(range-vector): 範圍向量內每一個度量指標的整體標準誤差。
  • `stdvar_over_time(range-vector): 範圍向量內每一個度量指標的整體標準方差。

請注意,即便值在整個時間間隔內的間隔不均勻,指定時間間隔內的全部值在聚合中都具備相同的權重。

PromQL例子

1、簡單的時間序列選擇

使用度量標準http_requests_total返回全部時間序列: 

http_requests_total

使用度量標準http_requests_total以及給定的jobhandler標籤返回全部時間系列:

http_requests_total{job="apiserver", handler="/api/comments"}

返回相同向量的整個時間範圍(在本例中爲5分鐘),使其成爲範圍向量:

http_requests_total{job="apiserver", handler="/api/comments"}[5m]

請注意,致使範圍向量的表達式不能直接繪製,而是在表達式瀏覽器的表格("Console")視圖中查看。

使用正則表達式,您只能爲名稱與特定模式匹配的做業選擇時間序列,在本例中爲全部以server結尾的做業。 請注意,這會進行子字符串匹配,而不是完整的字符串匹配:

http_requests_total{job=~"server$"}

要選擇除4xx以外的全部HTTP狀態代碼,您能夠運行:

http_requests_total{status!~"^4..$"}

2、子查詢

此查詢返回過去30分鐘的5分鐘 http_requests_total指標率,分辨率爲1分鐘:
rate(http_requests_total[5m])[30m:1m]

這是嵌套子查詢的示例。 deri函數的子查詢使用默認分辨率。 請注意,沒必要要地使用子查詢是不明智的。

max_over_time(deriv(rate(distance_covered_total[5s])[30s:5s])[10m:])

3、使用函數,操做符等

使用http_requests_total指標名稱返回全部時間序列的每秒速率,在過去5分鐘內測量:

rate(http_requests_total[5m])
假設http_requests_total時間序列都有標籤job(按做業名稱扇出)和instance(按做業實例扇出),咱們可能想要總結全部實例的速率,所以咱們獲得的輸出時間序列更少,但仍然 保留job維度
sum(rate(http_requests_total)[5m]) by (job)
若是咱們有兩個具備相同維度標籤的不一樣指標,咱們能夠對它們應用二元運算符,而且兩側具備相同標籤集的元素將匹配並傳播到輸出。 例如,此表達式爲每一個實例返回MiB中未使用的內存(在虛構的羣集調度程序上公開它運行的實例的這些度量標準):
(instance_memory_limit_byte - instant_memory_usage_bytes) / 1024 / 1024

相同的表達式,但由應用程序總結,能夠這樣寫:

sum( instance_memory_limit_bytes - instance_memory_usage_bytes) by (app, proc) / 1024 / 1024

若是相同的虛構集羣調度程序爲每一個實例公開了以下所示的CPU使用率指標:

instance_cpu_time_ns{app="lion", pro="web", rev="34d0f99", env="prod", job="cluster-manager"}
instance_cpu_time_ns{app="elephant", proc="worker", rev="34d0f99", env="prod", job="cluster-manager"}
instance_cpu_time_ns{app="turtle", proc="api", rev="4d3a513", env="prod", job="cluster-manager"}
...

咱們能夠按應用程序(app)和進程類型(proc)分組排名前3位的CPU用戶:

topk(3, sum(rate(instance_cpu_time_ns[5m])) by(app, proc))

假設此度量標準包含每一個運行實例的一個時間系列,您能夠計算每一個應用程序運行實例的數量,以下所示:

count(instance_cpu_time_ns) by (app)
相關文章
相關標籤/搜索