Prometheus 的查詢有一套專用語言,叫做 PromQL
。其表達式可能是受了 golang 的影響,非常的緊湊和符號化。這使得其易於書寫但難以理解(對不熟悉這種 DSL 的人來說)。因而有了這篇文章。
以下內容基於官方文檔(2.0)編譯。
數據類型
表達式的值一定屬於以下四種數據類型其一:
- 瞬時向量(Instant Vector)一組時序數據。其中每個時序都只有一個時間點,且一組數據的該時間點相同,比如今天 12:05:30 時所有服務器的 CPU 負載。
- 範圍向量(Range Vector)一組時序數據,但每個時序都有一段時間的採樣點。
- 標量(Scalar)單純的浮點數
- 字符串(String)單純的字符串(暫未使用)
向量和標量的區別僅在於向量是來自於時序數據的一個採樣點,因此其帶有時間戳、metric、labels 等屬性。
我們主要關注兩種向量的區別。從字面上來看,也許會覺得,畫圖(如 /graph
)用的是範圍向量,因爲畫圖就是畫的時序在一段時間範圍內採樣的值嘛。但其實能夠用來畫圖的只有 瞬時向量。Prometheus 的運算邏輯是這樣的:表達式只是返回一次計算的值,當畫圖的時候,先把總的時間段分割(downsample),然後分別計算每段上的瞬時向量,並賦予該時間段的起始時間戳。最後所有的段連接起來就是一張圖。有點像 map/reduce 的過程。
字面量
字面量是最簡單的一種表達式,所見即所得。但也有一些需要注意的地方,比如字符串。
單引號和雙引號作用類似,使用 "\"
來進行轉義。反引號括起來的字符串則完全不進行轉義。其轉義規則與 golang 相同。
時序查詢語句
瞬時向量查詢
即選取(select)一組時序數據的語句,是表達式的基本語句。從到現在的描述可以看出,PromeQL 並不明確區分一條和一組時序數據。可能在它的邏輯裏這兩者的本質是一樣的,一條不過是一組的一個特例而已。
最簡單的語句是一個 metric 名稱
http_requests_total
然後可以加一些過濾條件(label)
http_requests_total{job="prometheus",group="canary"}
label 運算也支持除 =
外的其他運算符號,比如 !=
不等於;=~
正則匹配;!~
正則不匹配。如
http_requests_total{environment=~"staging|testing|development",method!="GET"}
匹配運算有一個特殊問題就是如何處理空值。Prometheus 的方式是,key=""
這種可以匹配不包含該 key 的時序,而 key=~'.*'
這種同樣支持空值的正則表達式則只匹配包含該 key 的時序。
Prome 比較有趣的地方是支持不包含 metric 的查詢語句,前提是至少有一個 label 不匹配空值,即避免 select all
。
{job=~".+"} # Good!
{job=~".*"} # Bad!
更有趣的地方是,這種 label 匹配語句還可以匹配 metric 的名字,通過使用 __name__
這個內置變量:
{__name__=~"^http.*"}
範圍向量查詢
範圍向量的查詢語法就是在瞬時向量的後面加一個 []
標識從該瞬時向量的時間戳起向前選取多久的時間範圍。中括號內支持一系列的形如 \d+\s
的時間段表達式,表達式單位從小到大包含
s
m
h
d
w
y
注意裏面沒有月。一個主要的原因可能是月並非一個明確的時間段,另一個原因可能是和分鐘的首字母衝突。雖然可以用大寫 M 代替,但結合理由一,似乎引入這個單位帶來的麻煩比好處要多。
offset 修飾符
用來將查詢語句向更早平移的修飾符,可以修飾兩種向量。使用時需注意一定要緊貼查詢語句,如瞬時向量:
sum(http_requests_total{method="GET"} offset 5m) // GOOD.
sum(http_requests_total{method="GET"}) offset 5m // INVALID.
亦如範圍向量
rate(http_requests_total[5m] offset 1w)
運算符
像剛展示的 sum
, rate
等,PromeQL 支持很多二元或聚合運算符。他們的詳細描述可以參考:OPERATORS
聚合
提供一個分組 label 和一個運算方法,如:以 job 分組,每組qps求和:
sum(rate(http_requests_total[5m])) by (job)
運算
如果兩個 metric 的 label 完全匹配,那麼他們之間就可以進行四則運算,比如減法:
(instance_memory_limit_bytes - instance_memory_usage_bytes) / 1024 / 1024
回到瞬時向量和範圍向量上,可以看到運算符的運算過程是可以轉化這兩種向量的。比如最簡單的 sum
,可以把一個範圍向量加和成爲一個瞬時向量。這樣你在 /graph
裏不能展示的 http_requests_total[5m]
在套上一個 sum
後就可以畫圖了。
還有一個要注意的問題是 rate
和 sum
搭配的時候要注意順序:rate-then-sum-never-sum-then-rate
因爲運算符的種類細節並不影響對 PromeQL 的理解,所以這裏直接跳過。
函數
同上,參考:FUNCTIONS