日B视频 亚洲,啪啪啪网站一区二区,91色情精品久久,日日噜狠狠色综合久,超碰人妻少妇97在线,999青青视频,亚洲一区二卡,让本一区二区视频,日韩网站推荐

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

詳解Prometheus的數(shù)據(jù)類型

馬哥Linux運維 ? 來源:CSDN技術(shù)社區(qū) ? 2025-05-13 09:50 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

對于 Prometheus 生態(tài)的監(jiān)控系統(tǒng),PromQL 是必備技能,本文著重點講解這個查詢語言,摻雜一些生產(chǎn)實踐場景,希望對你有所幫助。

數(shù)據(jù)類型

Prometheus 有四種數(shù)據(jù)類型:Gauge、Counter、Histogram、Summary,其中最關(guān)鍵的是 Gauge 和 Counter,Histogram 和 Summary 只是為了上報監(jiān)控數(shù)據(jù)的 Client 側(cè)的便利,可以看做是組合使用了 Gauge 和 Counter。所以我們重點就來講解 Gauge 和 Counter 類型。

Gauge 類型

Gauge 類型的值表示當前的狀態(tài),可大可小、可負可正,比如某個虛機實例掛了,用 0 表示, 如果實例存活,用 1 表示;再比如內(nèi)存使用率,這個時刻采集是 33.7%,下個周期采集可能就 變成了 25.8%;還有像機器最近 5 分鐘的 load、正在運行的進程數(shù)量等等,都使用 Gauge 類 型來表示。這種類型的值,我們非常關(guān)注當前值。

Counter 類型

Counter 類型是單調(diào)遞增的值,比如機器上某塊網(wǎng)卡收到的數(shù)據(jù)包的總量,是從操作系統(tǒng)啟動 之后,就持續(xù)遞增的,對于這種類型的值,我們通常關(guān)注的不是當前值是多少,而是關(guān)注增量和 變化率。我們在機器上執(zhí)行 ifconfig 命令:

eth0: flags=4163 mtu 1500
inet 10.206.0.16 netmask 255.255.240.0 broadcast 10.206.15.255
inet6 fe80:ffa180 prefixlen 64 scopeid 0x20
ether 5200a1:80 txqueuelen 1000 (Ethernet)
RX packets 457952401 bytes 125894899868 (117.2 GiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 518040495 bytes 276312546157 (257.3 GiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

RX packets 后面的值是 OS 啟動以來收到的總的包量,TX packets 后面的值是 OS 啟動以來發(fā)出去的總的包量,都是很大的值,我們通常不太關(guān)注這個值當前是多少,更關(guān)注的是最近 1 分鐘收到/發(fā)出多少包,或者每秒收到/發(fā)出多少包。而對于監(jiān)控數(shù)據(jù)采集器而言,一般是周期性運行的,比如每 10 秒采集一次,每次采集網(wǎng)卡收到/發(fā)出的包這個數(shù)據(jù)的時候,都只能采集到當前的值,就像執(zhí)行 ifconfig 命令,每 10 秒執(zhí)行一次,每次都看到一個巨大的當前值,而且一次比一次大。如果采集器不做計算,把這個值原封不動上報給監(jiān)控服務(wù)端,那計算增量、計算速率這個需求,就要放到服務(wù)端來實現(xiàn)了,所以服務(wù)端必須要能對這種類型的數(shù)據(jù)建模抽象,也就是所謂的 Counter 類型。

時序數(shù)據(jù)

PromQL 就是查詢時序數(shù)據(jù)的一種 Query Language,要想對 PromQL 有了解,得先搞清楚時
序數(shù)據(jù)。

認識時序數(shù)據(jù)

我們先來看一張圖,圖上是 5 臺機器的內(nèi)存可用率:![

93771ff0-2b27-11f0-9310-92fbcf53809c.png

](https://img-blog.csdnimg.cn/direct/a8629b58178246378179466d21acb886.png)
每個機器的內(nèi)存可用率數(shù)據(jù),體現(xiàn)為圖上的一條線,我們稱為 series,某個機器在某一時刻的內(nèi)存可用率數(shù)據(jù),我們稱為數(shù)據(jù)點,比如上圖,2022-08-25 1522 這個時刻,每個機器都有一個可用率數(shù)據(jù)點,共計 5 個數(shù)據(jù)點。上面的圖是查詢的最近一小時的,我們切換到 Table 視圖,得到如下結(jié)果:

938dab6c-2b27-11f0-9310-92fbcf53809c.png

在這里插入圖片描述 這個表格的內(nèi)容,是這 5 臺機器在當前這個時間點的最新值,當前我做查詢的時刻是:2022-
08-25 1503 用 Chrome 開發(fā)者工具可以看到發(fā)的請求參數(shù):

93a639f2-2b27-11f0-9310-92fbcf53809c.png

在這里插入圖片描述
但是,監(jiān)控數(shù)據(jù)是周期性上報的,比如每 10 秒上報一次,在 2022-08-25 1503 這個時刻,未必恰好有監(jiān)控數(shù)據(jù)啊,那這個 Table 中的數(shù)據(jù)是哪里來的?
實際上,Prometheus 有個啟動參數(shù),–query.lookback-delta=2m 來控制這個行為,如果配置為 2m,就表示,Prometheus 會查詢 2022-08-25 1503 ~ 2022-08-25 1503 這 2分鐘之間的數(shù)據(jù),然后返回最新的那個。

查詢類型

上例中的 mem_available_percent{app=“clickhouse”} 稱為查詢表達式,不同的表達式,會返回不同的內(nèi)容,返回的內(nèi)容總共有 4 種格式,分別是:Instant vector(瞬時向量)、Rangevector(范圍向量)、Scalar(標量)、String(字符串)。返回瞬時向量的查詢表達式,我們
稱為 Instant Query,返回范圍向量的查詢表達式,我們稱為 Range Query。

上例中的 mem_available_percent{app=“clickhouse”} 既可以用于展示 Table 視圖,又可以用于展示 Graph 視圖,是典型的 Instant Query。

如果在表達式后面加上一個時間范圍,比如 1 分鐘:
mem_available_percent{app=“clickhouse”}[1m] 這個查詢表達式就變成了 Range Query,Range Query里有個時間范圍,其 Table 視圖的截圖如下:

93b9a35c-2b27-11f0-9310-92fbcf53809c.png

在這里插入圖片描述
第 4 臺機器相比其他的機器,返回了更多數(shù)據(jù),是因為那個機器的監(jiān)控數(shù)據(jù)采集頻率是 10s,而其他的機器采集頻率是 30s。

通過 range query + Table 視圖,可以讓我們直觀看到原始上報的監(jiān)控數(shù)據(jù)以及上報的具體時刻(對于排查監(jiān)控數(shù)據(jù)采集相關(guān)的問題尤為有用),如果在 Graph 視圖,返回的數(shù)據(jù)取決于 step 參數(shù),查詢時傳給時序庫的 step = 10,返回的圖形就是每 10s 一個點,step =20 就是每 20s 一個點,返回的數(shù)據(jù)的時間間隔取決于 step 參數(shù)而非原始數(shù)據(jù)的上報間隔。

Range Query 理論上是沒法繪制 Graph 的(當然有些時序庫可能會做容錯處理),因為從原理上說不通。繪圖的時候,我們要選擇一個時間范圍,比如最近一小時,然后傳給后端一個step 參數(shù)用于控制分辨率,即數(shù)據(jù)間隔,比如 step=60,即表示希望每個 series 每分鐘返回一個點,但如果是 Range Query,相當于在某個時刻返回多個點,這就無所適從了。

Prometheus 文檔中有一個章節(jié)專門介紹函數(shù),各個函數(shù)的介紹中,都會寫明是用于 instantvector,還是用于 range-vector,如果不理解查詢類型,就無法很好的應用這些函數(shù)。

查詢選擇器

PromQL大括號里的部分是 selector,查詢選擇器,用于從一大堆監(jiān)控數(shù)據(jù)中,過濾出真正關(guān)心的數(shù)據(jù),在 Prometheus 生態(tài)里,時序數(shù)據(jù)的標識,就是一堆標簽集合,所以這里的過濾,就是針對標簽做過濾,支持四類操作符:

? =:完全匹配,比如 app=“clickhouse”

? !=:完全不匹配,比如 app!=“clickhouse”

? =:正則匹配,比如 app=“n9e-.*”

? !:正則不匹配,比如 app!“n9e-.*”

指標名稱,通常放到大括號之外,但實際上,指標名稱也是一個標簽,其標簽Key是__name__,所以之前查詢的例子,可以這么寫:

{__name__="mem_available_percent", app="clickhouse"}

94b49df2-2b27-11f0-9310-92fbcf53809c.png

在這里插入圖片描述
仍然可以達成相同的效果。有時采集的監(jiān)控數(shù)據(jù)格式設(shè)計的不好,一些本該用 label 的信息,放到了 metric 名稱中了,此時就可以用name做一些正則匹配。

Offset

監(jiān)控系統(tǒng)里,經(jīng)常會有同環(huán)比的需求,比如,當前的值相比一周之前,是否有巨大變化,那怎么才能獲取歷史數(shù)據(jù)呢?可以使用 offset 關(guān)鍵字。
offset 后面跟一個時間段,比如 5m、1d、7d、1w,offset 要緊跟查詢選擇器,比如:

sum(http_requests_total{method="GET"} offset 1d)

運算符

PromQL 支持基本的算術(shù)運算符和比較運算符,可以對不同的即時向量做運算,這為監(jiān)控系統(tǒng)帶來了巨大的進步,算術(shù)運算符讓很多計算不需要在采集端做了,可以輕易挪到服務(wù)端,而比較運算符則為告警邏輯提供了支撐。

算術(shù)運算符

? (+) (addition)

? (-) (subtraction)

? (*) (multiplication)

? (/) (division)

? (%) (modulo)

? (^) (power/exponentiation)

舉一個例子來演示真實環(huán)境下的算術(shù)運算符的應用,比如之前的例子,對于內(nèi)存可用率的指標mem_available_percent 這個指標是采集器直接計算好的,如果采集器沒有計算,而是上報了原始指標 mem_available 和 mem_total,我們?nèi)匀豢梢允褂?promql 計算出可用率指標:

94d00f7e-2b27-11f0-9310-92fbcf53809c.png

在這里插入圖片描述
邏輯上,是先根據(jù) mem_available{app=“clickhouse”} 找到相關(guān)指標數(shù)據(jù),會找到5條,再根據(jù) mem_total{app=“clickhouse”} 也能找到5條,二者相除的邏輯姑且可以理解為,循環(huán)遍歷mem_available 的5條記錄,對于每一條,去 mem_total 的5條記錄中找標簽相同的記錄,進
行除法運算。除法運算得到5條結(jié)果(0~1之間的數(shù)字),然后跟100相乘(得到百分比大?。?,100這個數(shù)字稱為標量,5條結(jié)果和標量計算,會把每一條結(jié)果分別乘以100,得到最終的結(jié)果,這個最終結(jié)果其實就是 mem_available_percent。

如果分子和分母對應的selector查到的數(shù)據(jù)標簽不同,就沒法做除法運算了,比如
net_bytes_recv 比內(nèi)存相關(guān)的指標多了一個interface的標簽(標明網(wǎng)卡),二者是沒法做運算
的,結(jié)果為空:

net_bytes_recv{app="clickhouse"}/mem_total{app="clickhouse"}

比較運算符

? == (equal)
? != (not-equal)
? > (greater-than)
? < (less-than)
? >= (greater-or-equal)
? <= (less-or-equal)
比較運算符的最典型用法,就是一個 instant-vector 和一個標量之間的比較,比如
mem_available_percent{app=“clickhouse”} 的結(jié)果:

94ea09c4-2b27-11f0-9310-92fbcf53809c.png

在這里插入圖片描述
如果我們認為內(nèi)存可用率小于60就是有問題的,想找出所有有問題的數(shù)據(jù),只要在 promql 中拼上 < 60 即可:

950a7b3c-2b27-11f0-9310-92fbcf53809c.png

在這里插入圖片描述

如上的方法,其實就是告警引擎的核心邏輯。告警規(guī)則里會要求用戶配置promql以及執(zhí)行頻率,告警引擎就會根據(jù)執(zhí)行頻率周期性執(zhí)行,每次執(zhí)行的時候就是拿著promql去查詢,promql中帶有閾值,即上例中的 <60,所以如果所有機器的內(nèi)存可用率都很高,比如維持在80~90,
那這個promql是不會返回查詢結(jié)果的,此時監(jiān)控系統(tǒng)就認為一切正常。如果返回了結(jié)果,比如上例中返回了3條結(jié)果,告警引擎就會認為有異常產(chǎn)生,生成3個告警事件。

當然,有的時候,偶爾一次觸發(fā)了閾值我們認為不算啥事,希望連續(xù)觸發(fā)多次才告警,此時就要使用 prometheus alerting rule 的 for 關(guān)鍵字,或者夜鶯中的持續(xù)時長的配置,表示在一個時間范圍內(nèi)多次執(zhí)行,每次都觸發(fā)了才告警。

像上例觸發(fā)了3個告警事件,如果后面繼續(xù)周期性使用promql查詢查不到數(shù)據(jù)了,就說明最新的mem_available_percent數(shù)據(jù)不再小于60,即告警恢復。

邏輯/集合運算符

相關(guān)運算符有三個:and、or、unless 用于 instant-vector 之間的運算。首先來解釋一下各個運算符的行為。

and

vector1 and vector2,其結(jié)果是一個由vector1的元素組成的向量,對于這些元素,vector2中存在著完全匹配的標簽集,其他元素被刪除。metric的名稱和值從左邊的向量轉(zhuǎn)移過來。用于什么場景?先經(jīng)過 vector1 做過濾得到一批監(jiān)控數(shù)據(jù),可能里邊有一些是不想要的,可以用 and 操作符,再加一個條件,用另一個 metric 的值做一些二次過濾。舉例:

disk_used_percent{app="clickhouse"} > 70
and
disk_total{app="clickhouse"}/1024/1024/1024 < 500

磁盤利用率大于70%就告警,對于盤不大的情況是適用的,如果盤太大,比如16T一塊盤,使用率70%還有非常大的余量,所以這里我們使用and附加一個條件,限制一下disk_total,即磁盤總大小,磁盤總大小小于500GB,才適用磁盤利用率大于70%這個規(guī)則。

or

vector1 or vector2,其結(jié)果是一個向量,包含vector1的所有原始元素(標簽集+值)以及vector2中所有在vector1中沒有匹配標簽集的元素。

舉一個例子,比如系統(tǒng)負載,有最近1分鐘、最近5分鐘、最近15分鐘的負載,需求是:最近1分鐘的負載大于8或者最近5分鐘的負載大于8,就告警,promql寫法:

system_load1{app="clickhouse"} > 8
or
system_load5{app="clickhouse"} > 8

unless

vector1 unless vector2,結(jié)果是一個由vector1中的元素組成的向量,在vector2中沒有完全匹配標簽集的元素,兩個vector中的所有匹配元素都被刪除。姑且可以理解為一個減法,vector1- vector2。

舉個例子,還是磁盤利用率的問題,對于超過1個T的大盤,剩余量小于300G就告警,promql
怎么寫?

disk_free{app="clickhouse"}/1024/1024/1024 < 300
unless
disk_total{app="clickhouse"}/1024/1024/1024 < 1024

使用 unless 排除掉小于1個T的盤,剩下的就只剩大于1個T的大盤了,效果達成。

向量匹配

向量之間的操作試圖在右側(cè)的向量中為左側(cè)向量的每個條目找到一個匹配的元素,匹配行為分為:one-to-one、many-to-one、one-to-many。

on 和 ignoring

上面演示 and、or、unless 的例子,兩個vector的標簽集都是一樣的,那如果有些標簽略微有些差異,可以使用 on 和 ignoring 關(guān)鍵字來限制用于做匹配的標簽集。舉例:

mysql_slave_status_slave_sql_running == 0
and ON (instance)
mysql_slave_status_master_server_id > 0

這個promql想表達的意思是如果這個mysql實例是個slave(master_server_id>0),則檢查其slave_sql_running的值,如果slave_sql_running==0表示slave sql線程沒有在運行。

但是mysql_slave_status_slave_sql_running和mysql_slave_status_master_server_id這兩個metric的標簽可能并非完全一致,不過好在二者都有個instance標簽,且相同instance標簽的數(shù)據(jù)從語義上來看就表示一個實例的多個指標數(shù)據(jù),那就可以用on關(guān)鍵字,指定只使用instance
標簽做匹配,忽略其他標簽。

與on相反的是ignoring關(guān)鍵字,顧名思義,ignoring是忽略掉某些標簽,用剩下的標簽來做匹配。我們拿 Prometheus 文檔中的例子來說明:

## example series
method_coderate5m{method="get", code="500"} 24
method_coderate5m{method="get", code="404"} 30
method_coderate5m{method="put", code="501"} 3
method_coderate5m{method="post", code="500"} 6

method_coderate5m{method="post", code="404"} 21
methodrate5m{method="get"} 600
methodrate5m{method="del"} 34
methodrate5m{method="post"} 120
## promql
method_coderate5m{code="500"}
/ ignoring(code)
methodrate5m
## result
{method="get"} 0.04 // 24 / 600
{method="post"} 0.05 // 6 / 120

group_left 和 group_right

這兩個關(guān)鍵詞用于 one-to-many 和 many-to-one 的匹配場景,left、right 指向高基數(shù)的那一
側(cè)的 vector。還是拿上面的 method_coderate5m 和
methodrate5m 這倆指標來做例子,使用 group_left 的 promql 和結(jié)果如下:

## promql
method_coderate5m
/ ignoring(code) group_left
methodrate5m
## result
{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

比如針對 method=“get” 的條目,右側(cè)的vector中只有一個記錄,但是左側(cè)的vector中有兩個
記錄,所以高基數(shù)的一側(cè)是左側(cè),故而使用 group_left。
另外舉一個例子,說明 group_left group_right 的一個常見用法,比如我們使用 kube-statemetrics 來采集 Kubernetes 各個對象的指標數(shù)據(jù),其中針對 pod 有個指標是
kube_pod_labels,會把 pod 的一些信息放到這個指標的標簽里,指標值是1,相當于一個元信
息,比如:

kube_pod_labels{
[...]
  label_name="frontdoor",
  label_version="1.0.1",
  label_team="blue"
  namespace="default",
  pod="frontdoor-xxxxxxxxx-xxxxxx",
} = 1

假設(shè)某個 Pod 是接入層的,統(tǒng)計了很多 HTTP 請求相關(guān)的指標,我們想統(tǒng)計 5xx 的請求數(shù)量,希望能按 Pod 的 version 畫一個餅圖。這里有個難點:接入層這個 Pod 沒有 version 標簽,version 信息只是出現(xiàn)在 kube_pod_labels 中,如何讓二者聯(lián)動呢?上答案:

sum(
rate(http_request_count{code=~"^(?:5..)$"}[5m])) by (pod)
*
on (pod) group_left(label_version) kube_pod_labels

我們來掰開揉碎這個 promql 看一下具體的意思,乘號前面的部分,是一個典型的統(tǒng)計每秒5xx 數(shù)量的語法,group by pod。

然后我們乘以 kube_pod_labels,這個值是1,所以對整體數(shù)值沒有影響,而kube_pod_labels 有多個標簽,而且和sum語句的結(jié)果vector的標簽不一致,所以通過on(pod) 的語法指定只是按照pod標簽來做對應關(guān)系。

最后,利用 group_left(label_version) 把 label_version 附加到了結(jié)果向量中,高基數(shù)的部分顯然是sum的部分,所以是group_left而非group_right。

聚合運算

針對單個指標的多個 series,比如100臺機器的 mem_available_percent,可能會有一些聚合需求,比如想查看這100臺機器的平均內(nèi)存可用率,或者排個序,取數(shù)值最小的10臺。這種需求使用promql內(nèi)置的聚合函數(shù)來做。
? sum (calculate sum over dimensions)
? min (select minimum over dimensions)
? max (select maximum over dimensions)
? avg (calculate the average over dimensions)
? group (all values in the resulting vector are 1)
? stddev (calculate population standard deviation over dimensions)
? stdvar (calculate population standard variance over dimensions)
? count (count number of elements in the vector)
? count_values (count number of elements with the same value)
? bottomk (smallest k elements by sample value)
? topk (largest k elements by sample value)
? quantile (calculate φ-quantile (0 ≤ φ ≤ 1) over dimensions)

比如取平均值和取最小的2個可用率數(shù)據(jù),其對應的 promql 如下:

avg(mem_available_percent{app="clickhouse"})
bottomk(2, mem_available_percent{app="clickhouse"})

另外,我們有時會有分組統(tǒng)計的需求,比如我想分別統(tǒng)計clickhouse和canal的機器的內(nèi)存可用率,可以使用by關(guān)鍵字指定分組統(tǒng)計的維度(與by相反的是without):

avg(mem_available_percent{app=~"clickhouse|canal"}) by (app)

函數(shù)

Prometheus 函數(shù)非常多,具體文檔參考:https://prometheus.io/docs/prometheus/latest/querying/functions/ 這一節(jié)我們舉例說明一些常用的函數(shù)。

absent_over_time

接收一個 range-vector,如果range-vector是空,則返回1,表示absent,如果range-vector有內(nèi)容,則什么都不返回。
這個特性在生產(chǎn)環(huán)境下可以用作nodata告警,比如:

absent_over_time(system_load_norm_1{ident="tt-fc-dev02.nj"}[5m])

這個promql表示,tt-fc-dev02.nj 這個機器在最近5m內(nèi)如果上報過system_load_norm_1指標,即 tt-fc-dev02.nj 機器存活,則什么都不返回,如果機器掛了,不再上報監(jiān)控數(shù)據(jù)了,即指標在最近5m內(nèi)不存在了,即可判斷機器失聯(lián)。

這種方法有個弊端,就是得把指標的所有標簽都寫上,比如我們的需求可能是,100臺機器,任何一臺失聯(lián)了就告警,想當然的我們可能會這么寫:

absent_over_time(system_load_norm_1[5m])

很遺憾,這個結(jié)果不符合預期,只要任一臺機器有在上報監(jiān)控數(shù)據(jù),這個promql就返回空,即使已經(jīng)有99臺機器掛了,還剩最后一臺機器在上報監(jiān)控數(shù)據(jù),這個promql也仍然返回空。

所以實際上,如果我們想要對100臺機器使用absent_over_time做失聯(lián)告警,就要配置100條告警規(guī)則,每個規(guī)則里的promql都要把機器標識信息寫上。

對于拉模式的監(jiān)控系統(tǒng),比如 Prometheus,很容易判斷機器失聯(lián),因為 pull 不到數(shù)據(jù)
了,就知道 target 掛了,通過 up 指標就可以告警;對于推模式的監(jiān)控系統(tǒng),比如 OpenFalcon、Datadog、Nightingale,就不好搞了。所以夜鶯的告警規(guī)則里專門做了一個機器
告警類型,用于機器失聯(lián)告警。

increase

這個函數(shù)很常用,但是其計算結(jié)果可能會出乎意料,這一節(jié)詳細講解,打消各位的疑問。字面意思上,表示求取一個增量,接收一個 range-vector,range-vector 顯然是會返回多個value+timestamp 的組合,我們直觀理解就是,直接把時間范圍內(nèi)最后一個值減去第一個值,不就可以得到增量了嗎?非也!如下圖:

95631224-2b27-11f0-9310-92fbcf53809c.png

在這里插入圖片描述
這個圖上的一些關(guān)鍵信息,我們摘錄出文本,具體如下:

promql: net_bytes_recv{interface="eth0"}[1m] @ 1661570908
965304237246 @1661570850
965307953982 @1661570860
965311949925 @1661570870
965315732812 @1661570880
965319998347 @1661570890
965323899880 @1661570900

promql: increase(net_bytes_recv{interface="eth0"}[1m]) @1661570909
23595160.8

監(jiān)控數(shù)據(jù)是10秒上報一次,所以雖然兩次 promql 查詢時間不同,一次是 1661570908,一次是 1661570909,但是所查詢的原始數(shù)據(jù)內(nèi)容是一樣的,就是 1661570850~1661570900 這幾個時間點對應的數(shù)據(jù)。

直觀上理解,在這幾個時間點對應的數(shù)據(jù)上求取 increase,無非就是最后一個值減去第一個值,即965323899880-965304237246=19662634,很遺憾,實際結(jié)果是23595160.8,差別有點大,顯然這個直觀理解的算法是錯的。
實際上,increase 這個 promql 發(fā)起請求的時間是1661570909,時間范圍是[1m],相當于告訴Prometheus,我要查詢1661570849(1661570909-60)~1661570909之間的 increase數(shù)值。但是原始監(jiān)控數(shù)據(jù)并沒有 1661570849、1661570909 這兩個時刻的數(shù)值,怎么辦呢?Prometheus只能基于現(xiàn)有的數(shù)據(jù)做外推,即使用最后一個點的數(shù)值減去第一個點的數(shù)值,得到的結(jié)果除以時間差,再乘以60,即:

(965323899880.0-965304237246.0)/(1661570900.0-1661570850.0)*60=
23595160.8

上例中,我的測試數(shù)據(jù)是沒有缺失數(shù)據(jù)點的,如果有缺失數(shù)據(jù)點的情況,數(shù)據(jù)外推會更為
復雜,具體可以參考這篇文章:https://mp.weixin.qq.com/s/9aiqrtLTnzysV9olMx-rzA

rate

趁熱打鐵,說一下 rate 函數(shù),increase 函數(shù)是求取的時間段內(nèi)的增量,而且有數(shù)據(jù)外推,rate函數(shù)則求取的每秒變化率,也有數(shù)據(jù)外推的邏輯,相當于 increase 的結(jié)果除以 range-vector的時間段的大小,就是 rate 的值。我們用如下 promql 做驗證:

rate(net_bytes_recv{interface="eth0"}[1m])
== bool
increase(net_bytes_recv{interface="eth0"}[1m])/60.0

這里 == 后面跟了一個 bool 修飾符,表示希望返回一個 bool 值,如果是 true 就會返回 1,如
果是 false 就返回 0,我們觀察結(jié)果會發(fā)現(xiàn),這個表達式永遠都會返回 1,即等號前后的兩個
promql 語義上是相同的。

irate

rate 函數(shù)求取的變化率,相對平滑,因為是拿時間范圍內(nèi)的最后一個值和第一個值做數(shù)據(jù)外推,一些毛刺現(xiàn)象就會被平滑掉,如果想要得到更敏感的數(shù)據(jù),可以使用 irate 函數(shù)。irate 是拿時間范圍內(nèi)的最后兩個值來做計算,變化就會更劇烈,我們還是拿網(wǎng)卡入向流量這個指標來做個對比:

95850bfe-2b27-11f0-9310-92fbcf53809c.png

在這里插入圖片描述
藍色的更變化更劇烈的線是 irate 函數(shù)計算的,紫色的相對平滑的線是 rate 函數(shù)計算得到的。

histogram_quantile

要了解 histogram_quantile 函數(shù)的用法,首先得了解 Histogram 類型的數(shù)據(jù)。Histogram 翻譯過來是柱狀圖,設(shè)計這個數(shù)據(jù)類型,是為了描述響應延時的情況。

比如接口:/api/v1/query,如何度量這個接口的健康狀況?最核心有兩個指標,一個是成功率,一個是延遲,成功率的計算代價比較小,只需要為每個請求指標打上 statuscode 的標簽即可,然后可以求取非 5xx 非 4xx 的請求占比,即可得到成功的數(shù)量,除以總量就是成功率。

而對于延遲,如果只是求取平均延遲,代價也比較小,只要把請求總量做成一個 Counter 指標,把耗時總量做成一個 Counter 指標即可。但是,平均響應時間有時并不能很好的反應長尾問題,比如最近1分鐘有1萬個請求,大部分請求都是1秒內(nèi)返回,有200個請求是10秒返回,平均響應時間是:1.18秒,看起來還不錯,導致我們忽略了這200個長尾請求,而這200個長尾請求,可能恰好是暴露問題的200個請求。

所以在看延遲數(shù)據(jù)時,我們通常會用分位值,比如99分位,90分位,50分位,所謂的分位值,就是把一段時間內(nèi)的所有延遲數(shù)據(jù)從小到大排序,99分位就是看第99%位置的那個值的大小。還是上面的例子,平均響應時間是1.18秒,但是99分位時間是10秒,相差巨大,更容易暴露問題。這里所謂的99分位延遲10秒,可以理解為,99%的請求都在10秒內(nèi)返回。

從監(jiān)控系統(tǒng)角度,如何來存儲和計算出99分位值呢?如果每分鐘有1億個請求,難道真的要在監(jiān)控系統(tǒng)中存儲這1億個請求,然后排序,然后求取分位值?那這個代價就太大了。監(jiān)控數(shù)據(jù)是采樣數(shù)據(jù),對準確性要求沒有那么的高,有沒有什么辦法可以降低這個代價呢?這就是Prometheus Histogram 的設(shè)計初衷了。

Histogram 類型,是把延遲數(shù)據(jù)分到多個桶里,比如下面的例子,我們查詢一個bucket指標看看效果,雖然這個指標的桶劃分不是很合理,也可以說明問題:

959fa658-2b27-11f0-9310-92fbcf53809c.png

在這里插入圖片描述
binlog_consumer_latency_seconds_bucket 這個指標,有一個非常非常重要的標簽叫 le,表示桶上界,上面的例子就表示,binlog的consume延遲數(shù)據(jù)分成了6個桶,分別統(tǒng)計了每個桶的總的consume次數(shù):

延遲小于 0.01 秒的次數(shù): 1
延遲小于 0.1 秒的次數(shù): 321
延遲小于 1 秒的次數(shù): 14588
延遲小于 5 秒的次數(shù): 56826
延遲小于 10 秒的次數(shù): 56843
延遲小于 30 秒的次數(shù): 56881
延遲小于 60 秒的次數(shù): 56975
所有consume總數(shù) : 120396

假設(shè)我們統(tǒng)計50分位,那就是120396*0.5=60198.0,落到了 le=“+Inf” 這個桶里了,所以我們斷定50分位的值一定是大于60秒的,當然,因為這個桶劃分不是很合理,導致,90分位、99分位,定然也是在 le=“+Inf” 桶里,即值一定是大于60秒的,因為 le=“+Inf” 這個桶沒有上界,導致我們無法區(qū)分這幾個分位值。

下面我們假設(shè)一個指標及其數(shù)據(jù),做一個算法演示,假設(shè)指標名是http_request_duration_seconds_bucket ,其各個 bucket 的值如下:

http_request_duration_seconds_bucket{job="n9e-proxy", le="0.1"} 500
http_request_duration_seconds_bucket{job="n9e-proxy", le="1"} 700
http_request_duration_seconds_bucket{job="n9e-proxy", le="10"} 850
http_request_duration_seconds_bucket{job="n9e-proxy", le="20"} 1000
http_request_duration_seconds_bucket{job="n9e-proxy", le="+Inf"} 1000

根據(jù)這個數(shù)據(jù),我們可以計算出落在各個延遲區(qū)間的請求數(shù)量,如下:

0 ~ 0.1 : 500
0.1 ~ 1 : 200
1 ~ 10 : 150
10 ~ 20 : 150
20 ~ +Inf : 0

總共有1000個請求,我們來計算其90分位的值,即1000*0.9=900,第900個請求,顯然,第900個請求落在了1020這個區(qū)間,即90分位的延遲是10秒20秒,那具體是多少?其實是無法知曉的,不過 Prometheus 的 histogram_quantile 有個估計算法,它假設(shè)落在各個 bucket
的數(shù)據(jù)是均勻分布的,即10~20這個區(qū)間的150個請求,延遲最小的那個請求是10s,延遲最大的那個請求是20秒,總的第900個請求,就是這個區(qū)間的第50個請求,其延遲數(shù)據(jù)大概是:

(20-10)*(50/150)+10=13s

這是假設(shè)數(shù)據(jù)是均勻分布在各個桶的,假設(shè)10~20那個桶的150個請求,最大延遲的那個請求,其延遲數(shù)據(jù)是11秒,而這里算出13秒,顯然與現(xiàn)實不符,不符也沒辦法,這本來就是個預估值,知道大概數(shù)量級就可以了,還是那句話,監(jiān)控數(shù)據(jù)是采樣數(shù)據(jù),這么計算雖然不是那么準確,但是成本低。

實際上,我們基于某個指標的歷史所有數(shù)據(jù)計算分位值,意義不大,通常我們是基于最近一段時間的增量數(shù)據(jù)來計算,比如基于10分鐘區(qū)間的增量數(shù)據(jù)計算,就可以較為方便的知道,當前這個10分鐘的延遲是多少,上一個10分鐘的延遲是多少。histogram_quantile 接收兩個參數(shù),第一個是分位標量,第二個 instant-vector(這個vector的標簽中一定要有 le 標簽),舉例:

histogram_quantile(0.9, rate(http_request_duration_seconds_bucket[10m]))

上面的例子,是會對每個請求分別做計算,假設(shè)有兩個模塊:n9e-proxy、n9e-webapi,都統(tǒng)計了 http_request_duration_seconds_bucket ,我們可能希望以模塊為顆粒度,分別計算每個模塊的90分位延遲,寫法是:

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

注意,這里通過job標簽來區(qū)分模塊,le是計算histogram_quantile必須的,所以也要放到sum by后面,如果我們要計算全部數(shù)據(jù)的90分位值呢(雖然這大概率是個偽需求)?

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

針對分位值的計算,已經(jīng)闡述清楚了,但是分位值的計算是個挺重的查詢,可能會把后端時序庫打爆,所以很多公司可能在業(yè)務(wù)埋點SDK中不提供histogram這種方式,只提供summary方式。

所謂的summary,也是prometheus的一種埋點數(shù)據(jù)類型,summary也可以計算90分位、99分位的值,但是這個值不是通過promql在服務(wù)端計算的,而是在應用的內(nèi)存里,在SDK層面計算的,即客戶端把這個分位值算好,再上報給服務(wù)端,服務(wù)端就無需通過histogram_quantile
這么重的函數(shù)做計算了,而是直接查看就好。

但是,既然是在客戶端SDK層面計算,就會產(chǎn)生局限,這些分位值只能是實例級別(或者說進程
級別,因為SDK是在應用進程里運行的)的分位值,這個是否個問題?

筆者看來,這是個問題,但是這個問題不是特別嚴重,如果要求全局的90分位值,可以把所有實例的90分位值取個平均,雖然不是那么準確,也湊合能用。而實際上,對于一個服務(wù)部署多個實例的場景,通常這多個實例是負載均衡的,查看其中一個實例的分位值和查看總體的分位值理論上差不太多。而且,如果某個機器有問題,比如某個機器磁盤故障,導致部署在上面的實例異常,延遲變高,其他實例都是正常的,全局查看延遲數(shù)據(jù)的時候,每個實例是一條曲線,那個故障的機器,對應的曲線應該是恰好嚴重偏離其他曲線,正好可以借機知道具體是哪個實例/機器出了問題。

_over_time

這類聚合函數(shù)和聚合運算章節(jié)提供的sum、avg等聚合運算符非常像,容易混淆,著重做一個說明,比如avg,參數(shù)是instant-vector,是在同一時刻,對多個series的多個值求平均,而avg_over_time,參數(shù)是 range-vector,是根據(jù)指定的時間范圍,求取時間范圍內(nèi)的多個值的
平均。

比如 avg_over_time(mem_available_percent{ident=“10.3.4.5”}[1m]) 是取10.3.4.5這個機器的內(nèi)存可用率,取其最近1分鐘內(nèi)的多個值(如果10秒上報一次,1分鐘內(nèi)有6個值),求平均。

更多函數(shù)就不過多介紹了,相對容易理解,參考 Prometheus 官方文檔即可。最后擴展介紹一個 MetricsQL(MetricsQL 是 VictoriaMetrics 提供的一種查詢語言,兼容 PromQL 并對其做了增強,如果你的存儲是 VictoriaMetrics,則可以使用這些擴展函數(shù)) 中的擴展函數(shù)。

count_gt_over_time

假設(shè)原始需求:某個指標( 假設(shè)指標名字是 interface_status )每分鐘上報一次,如果 5 分鐘
內(nèi)有 3 次大于 10,就報警。使用 PromQL 比較難寫,使用 MetricsQL 就非常簡單:

count_gt_over_time(interface_status[5m], 10) >= 3

看到這個寫法,基本能直觀理解其含義了, count_gt_over_time(series_selector[d], gt) 函數(shù)有兩個參數(shù),一個是 range-vector,一個是標量 gt,表示在 range-vector 中大于 gt 的個數(shù),如果大于等于 3,就報警。除了 count_gt_over_time 函數(shù)之外,還有count_le_over_time、count_ne_over_time、count_eq_over_time 道理相同。

小結(jié)

上面的知識點是 PromQL 的常規(guī)知識,盡量融入了一些生產(chǎn)實踐的場景,當然,PromQL 還有更多函數(shù)沒有介紹,大家可以閱讀其文檔學習。

鏈接:https://blog.csdn.net/weixin_38908201/article/details/136302699

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 監(jiān)控系統(tǒng)

    關(guān)注

    21

    文章

    4189

    瀏覽量

    185180
  • 時序
    +關(guān)注

    關(guān)注

    5

    文章

    411

    瀏覽量

    39020
  • 數(shù)據(jù)類型
    +關(guān)注

    關(guān)注

    0

    文章

    238

    瀏覽量

    14235
  • Prometheus
    +關(guān)注

    關(guān)注

    0

    文章

    36

    瀏覽量

    2077

原文標題:運維/DevOps 必學!PromQL 入門指南,輕松玩轉(zhuǎn) Prometheus

文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    史上最全Python數(shù)據(jù)類型詳解

    數(shù)據(jù)類型是每個編程語言必不可少的基礎(chǔ)知識,也是必須要掌握的技能,很多人知識簡單的進行理解,并沒有很系統(tǒng)的進行知識的梳理,以下是對python語言的全部數(shù)據(jù)類型詳細匯總:Python中可以自定義
    發(fā)表于 06-15 14:57

    vhdl數(shù)據(jù)類型

    VHDL中的標識符可以是常數(shù)、變量、信號、端口、子程序或參數(shù)的名字。VHDL中的數(shù)據(jù)類型可以分成四大類: 標量型(SCALAR TYPE):屬單元素的最基本的數(shù)據(jù)類型,通常用于描述一個單值數(shù)據(jù)對象
    發(fā)表于 03-30 15:59 ?11次下載

    labview數(shù)據(jù)類型簡介

    labview數(shù)據(jù)類型簡介
    發(fā)表于 01-11 09:42 ?6次下載

    Struct結(jié)構(gòu)數(shù)據(jù)類型

    Struct類型是一種由多個不同數(shù)據(jù)類型元素組成的數(shù)據(jù)結(jié)構(gòu),其元素可以是基本數(shù)據(jù)類型,也可以是Struct、數(shù)組等復雜數(shù)據(jù)類型以及PLC
    的頭像 發(fā)表于 07-25 17:02 ?4101次閱讀

    結(jié)構(gòu)數(shù)據(jù)類型(Struct)及應用案例

    Struct數(shù)據(jù)類型使用非常靈活,隨時可以使用,但是相對于PLC數(shù)據(jù)類型 (UDT) 有以下缺點,所以建議需要使用Struct類型時,可以使用PLC數(shù)據(jù)類型(UDT)代替。
    的頭像 發(fā)表于 07-27 16:10 ?2955次閱讀

    什么是數(shù)據(jù)類型轉(zhuǎn)換

    常用的3種數(shù)據(jù)類型:1、Python數(shù)據(jù)類型第一種:字符串(str)。 2、Python數(shù)據(jù)類型第二種:整數(shù)(int)。 3、Python數(shù)據(jù)類型第三種:浮點數(shù)(float)。
    的頭像 發(fā)表于 02-23 15:21 ?2850次閱讀

    定義數(shù)據(jù)類型

    在運算之前我們必須首先定義出數(shù)據(jù)類型,定義出腳本支持的數(shù)據(jù)類型,這是運算的基礎(chǔ)。 這一小節(jié)我們將定義出數(shù)據(jù)類型,在這里我們暫時定義四個數(shù)據(jù)類型:
    的頭像 發(fā)表于 03-03 10:10 ?2115次閱讀

    PLC數(shù)據(jù)類型

    基本數(shù)據(jù)類型 ? ? ? 基本數(shù)據(jù)類型? ? 包括位、位序列、整數(shù)、浮點數(shù)、日期時間。(常見的) 1、位 字節(jié) 字 雙字 2、數(shù)據(jù)類型 3 浮點數(shù) 實(或浮點)數(shù)以 32 位單精度數(shù) (Real
    發(fā)表于 04-17 15:49 ?0次下載
    PLC<b class='flag-5'>數(shù)據(jù)類型</b>

    基本數(shù)據(jù)類型分享

    基本數(shù)據(jù)類型 基本數(shù)據(jù)類型:包括位、位序列、整數(shù)、浮點數(shù)、日期時間。此外字符也屬于基本數(shù)據(jù)類型,請參見文檔String與WString。 1.位和位序列 2.整數(shù)數(shù)據(jù)類型 3.浮點型實
    的頭像 發(fā)表于 06-13 14:14 ?1.4w次閱讀
    基本<b class='flag-5'>數(shù)據(jù)類型</b>分享

    ARRAY 數(shù)據(jù)類型的變量

    要求 全局數(shù)據(jù)塊已打開。 操作步驟 要聲明一個 ARRAY 數(shù)據(jù)類型的變量,請按以下步驟操作: 在“名稱”(Name) 列中,輸入變量的名稱。 在“數(shù)據(jù)類型”列中輸入“Array”數(shù)據(jù)類型
    的頭像 發(fā)表于 07-06 11:08 ?2678次閱讀

    F型PLC數(shù)據(jù)類型與標準PLC數(shù)據(jù)類型(UDT)之間的差別在哪?

    可以像使用標準 PLC 數(shù)據(jù)類型 (UDT) 那樣,聲明和使用 F 型 PLC 數(shù)據(jù)類型 (UDT) ??梢栽诎踩绦蛑幸约皹藴视脩舫绦蛑惺褂?F 型 PLC 數(shù)據(jù)類型 (UDT) 。
    的頭像 發(fā)表于 08-27 09:54 ?2213次閱讀
    F型PLC<b class='flag-5'>數(shù)據(jù)類型</b>與標準PLC<b class='flag-5'>數(shù)據(jù)類型</b>(UDT)之間的差別在哪?

    Redis的數(shù)據(jù)類型有哪些

    Redis的數(shù)據(jù)類型有哪些?有五種常用數(shù)據(jù)類型:String、Hash、Set、List、SortedSet。以及三種特殊的數(shù)據(jù)類型:Bitmap、HyperLogLog、Geospatial
    的頭像 發(fā)表于 10-09 10:51 ?1700次閱讀

    oracle的數(shù)據(jù)類型有哪些

    Oracle數(shù)據(jù)庫中有許多數(shù)據(jù)類型可供選擇,每種數(shù)據(jù)類型都有其各自的特點和適用場景。下面是對Oracle數(shù)據(jù)庫中最常用的數(shù)據(jù)類型的詳盡說明,
    的頭像 發(fā)表于 12-05 16:45 ?3972次閱讀

    plc數(shù)據(jù)類型怎么理解和應用

    PLC(可編程邏輯控制器)是一種工業(yè)自動化設(shè)備,用于控制機械和工業(yè)過程。在PLC編程中,數(shù)據(jù)類型是非常重要的概念,因為它決定了程序中數(shù)據(jù)的存儲和處理方式。正確理解和應用PLC數(shù)據(jù)類型是編寫有效、可靠
    的頭像 發(fā)表于 12-19 11:39 ?7065次閱讀

    SQL 通用數(shù)據(jù)類型

    SQL 通用數(shù)據(jù)類型 數(shù)據(jù)庫表中的每個列都要求有名稱和數(shù)據(jù)類型。Each column in a database table is required to have a name and a
    的頭像 發(fā)表于 08-18 09:46 ?888次閱讀
    平和县| 东源县| 庄河市| 阿图什市| 定南县| 保靖县| 华宁县| 和林格尔县| 醴陵市| 平乡县| 扬州市| 安徽省| 漳平市| 慈利县| 梅州市| 木兰县| 普兰店市| 建昌县| 连山| 临沂市| 城步| 库尔勒市| 肥城市| 宾川县| 黄梅县| 康保县| 海淀区| 神农架林区| 大英县| 余江县| 翁牛特旗| 陆河县| 北辰区| 福州市| 乌鲁木齐县| 新蔡县| 二连浩特市| 太康县| 易门县| 玉溪市| 岗巴县|