PromQL操作符


PromQL操作符

使用PromQL除了能夠方便的按照查詢和過濾時間序列以外,PromQL還支持豐富的操作符,用戶可以使用這些操作符對進一步的對事件序列進行二次加工。這些操作符包括:數學運算符,邏輯運算符,布爾運算符等等。

數學運算

例如,我們可以通過指標node_memory_free_bytes_total獲取當前主機可用的內存空間大小,其樣本單位為Bytes。這是如果客戶端要求使用MB作為單位響應數據,那只需要將查詢到的時間序列的樣本值進行單位換算即可:

node_memory_free_bytes_total / (1024 * 1024)

node_memory_free_bytes_total表達式會查詢出所有滿足表達式條件的時間序列,在上一小節中我們稱該表達式為瞬時向量表達式,而返回的結果成為瞬時向量。

當瞬時向量與標量之間進行數學運算時,數學運算符會依次作用域瞬時向量中的每一個樣本值,從而得到一組新的時間序列。

而如果是瞬時向量與瞬時向量之間進行數學運算時,過程會相對復雜一點。 例如,如果我們想根據node_disk_bytes_written和node_disk_bytes_read獲取主機磁盤IO的總量,可以使用如下表達式:

node_disk_bytes_written + node_disk_bytes_read

那這個表達式是如何工作的呢?依次找到與左邊向量元素匹配(標簽完全一致)的右邊向量元素進行運算,如果沒找到匹配元素,則直接丟棄。同時新的時間序列將不會包含指標名稱。 該表達式返回結果的示例如下所示:

{device="sda",instance="localhost:9100",job="node_exporter"}=>1634967552@1518146427.807 + 864551424@1518146427.807
{device="sdb",instance="localhost:9100",job="node_exporter"}=>0@1518146427.807 + 1744384@1518146427.807

PromQL支持的所有數學運算符如下所示:

  • + (加法)
  • - (減法)
  • * (乘法)
  • / (除法)
  • % (求余)
  • ^ (冪運算)

使用布爾運算過濾時間序列

在PromQL通過標簽匹配模式,用戶可以根據時間序列的特征維度對其進行查詢。而布爾運算則支持用戶根據時間序列中樣本的值,對時間序列進行過濾。

例如,通過數學運算符我們可以很方便的計算出,當前所有主機節點的內存使用率:

(node_memory_bytes_total - node_memory_free_bytes_total) / node_memory_bytes_total

而系統管理員在排查問題的時候可能只想知道當前內存使用率超過95%的主機呢?通過使用布爾運算符可以方便的獲取到該結果:

(node_memory_bytes_total - node_memory_free_bytes_total) / node_memory_bytes_total > 0.95

瞬時向量與標量進行布爾運算時,PromQL依次比較向量中的所有時間序列樣本的值,如果比較結果為true則保留,反之丟棄。

瞬時向量與瞬時向量直接進行布爾運算時,同樣遵循默認的匹配模式:依次找到與左邊向量元素匹配(標簽完全一致)的右邊向量元素進行相應的操作,如果沒找到匹配元素,則直接丟棄。

目前,Prometheus支持以下布爾運算符如下:

  • == (相等)
  • != (不相等)
  • > (大於)
  • < (小於)
  • >= (大於等於)
  • <= (小於等於)

使用bool修飾符改變布爾運算符的行為

布爾運算符的默認行為是對時序數據進行過濾。而在其它的情況下我們可能需要的是真正的布爾結果。例如,只需要知道當前模塊的HTTP請求量是否>=1000,如果大於等於1000則返回1(true)否則返回0(false)。這時可以使用bool修飾符改變布爾運算的默認行為。 例如:

http_requests_total > bool 1000

使用bool修改符后,布爾運算不會對時間序列進行過濾,而是直接依次瞬時向量中的各個樣本數據與標量的比較結果0或者1。從而形成一條新的時間序列。

http_requests_total{code="200",handler="query",instance="localhost:9090",job="prometheus",method="get"}  1
http_requests_total{code="200",handler="query_range",instance="localhost:9090",job="prometheus",method="get"}  0

同時需要注意的是,如果是在兩個標量之間使用布爾運算,則必須使用bool修飾符

2 == bool 2 # 結果為1

 

使用集合運算符

使用瞬時向量表達式能夠獲取到一個包含多個時間序列的集合,我們稱為瞬時向量。 通過集合運算,可以在兩個瞬時向量與瞬時向量之間進行相應的集合操作。目前,Prometheus支持以下集合運算符:

  • and (並且)
  • or (或者)
  • unless (排除)

vector1 and vector2 會產生一個由vector1的元素組成的新的向量。該向量包含vector1中完全匹配vector2中的元素組成。

vector1 or vector2 會產生一個新的向量,該向量包含vector1中所有的樣本數據,以及vector2中沒有與vector1匹配到的樣本數據。

vector1 unless vector2 會產生一個新的向量,新向量中的元素由vector1中沒有與vector2匹配的元素組成。

操作符優先級

對於復雜類型的表達式,需要了解運算操作的運行優先級

例如,查詢主機的CPU使用率,可以使用表達式:

100 * (1 - avg (irate(node_cpu{mode='idle'}[5m])) by(job) )

其中irate是PromQL中的內置函數,用於計算區間向量中時間序列每秒的即時增長率。關於內置函數的部分,會在下一節詳細介紹。

在PromQL操作符中優先級由高到低依次為:

  1. ^
  2. *, /, %
  3. +, -
  4. ==, !=, <=, <, >=, >
  5. and, unless
  6. or

匹配模式詳解

向量與向量之間進行運算操作時會基於默認的匹配規則:依次找到與左邊向量元素匹配(標簽完全一致)的右邊向量元素進行運算,如果沒找到匹配元素,則直接丟棄。

接下來將介紹在PromQL中有兩種典型的匹配模式:一對一(one-to-one),多對一(many-to-one)或一對多(one-to-many)。

一對一匹配

一對一匹配模式會從操作符兩邊表達式獲取的瞬時向量依次比較並找到唯一匹配(標簽完全一致)的樣本值。默認情況下,使用表達式:

vector1 <operator> vector2

在操作符兩邊表達式標簽不一致的情況下,可以使用on(label list)或者ignoring(label list)來修改便簽的匹配行為。使用ignoreing可以在匹配時忽略某些便簽。而on則用於將匹配行為限定在某些便簽之內。

<vector expr> <bin-op> ignoring(<label list>) <vector expr>
<vector expr> <bin-op> on(<label 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="500"} 6
method_code:http_errors:rate5m{method="post", code="404"} 21
method:http_requests:rate5m{method="get"}  600
method:http_requests:rate5m{method="del"}  34
method:http_requests:rate5m{method="post"} 120

 

使用PromQL表達式:

method_code:http_errors:rate5m{code="500"} / ignoring(code) method:http_requests:rate5m

該表達式會返回在過去5分鍾內,HTTP請求狀態碼為500的在所有請求中的比例。如果沒有使用ignoring(code),操作符兩邊表達式返回的瞬時向量中將找不到任何一個標簽完全相同的匹配項。

因此結果如下:

{method="get"}  0.04            //  24 / 600
{method="post"} 0.05            //   6 / 120

同時由於method為put和del的樣本找不到匹配項,因此不會出現在結果當中。

多對一和一對多

多對一和一對多兩種匹配模式指的是“一”側的每一個向量元素可以與”多”側的多個元素匹配的情況。在這種情況下,必須使用group修飾符:group_left或者group_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>

多對一和一對多兩種模式一定是出現在操作符兩側表達式返回的向量標簽不一致的情況。因此需要使用ignoring和on修飾符來排除或者限定匹配的標簽列表。

例如,使用表達式:

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

該表達式中,左向量method_code:http_errors:rate5m包含兩個標簽method和code。而右向量method:http_requests:rate5m中只包含一個標簽method,因此匹配時需要使用ignoring限定匹配的標簽為code。 在限定匹配標簽后,右向量中的元素可能匹配到多個左向量中的元素
因此該表達式的匹配模式為多對一,需要使用group修飾符group_left指定左向量具有更好的基數。

最終的運算結果如下:

{method="get", code="500"}  0.04            //  24 / 600
{method="get", code="404"}  0.05            //  30 / 600
{method="post", code="500"} 0.05            //   6 / 120
{method="post", code="404"} 0.175           //  21 / 120

提醒:group修飾符只能在比較和數學運算符中使用。在邏輯運算and,unless和or才注意操作中默認與右向量中的所有元素進行匹配。


免責聲明!

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



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