錯誤 1:高基數(shù)炸彈
這是 Prometheus 使用者經(jīng)常會犯的一個錯,因為 Prometheus 時序是基于多標(biāo)簽的,它非常靈活,有時你想新增一個標(biāo)簽,從而將一個粗粒度的指標(biāo)進行拆分,但切記添加的標(biāo)簽的值應(yīng)該做到盡量收斂,不然會導(dǎo)致同一指標(biāo)名的標(biāo)簽數(shù)量巨大而導(dǎo)致 Prometheus 嚴(yán)重的性能問題(OOM)。
舉個例子,您有一個只包含 method 標(biāo)簽的時間序列 http_requests_total:
http_requests_total{method="POST"} http_requests_total{method="GET"} http_requests_total{method="PUT"} http_requests_total{method="DELETE"}
這個時間序列定義沒問題,因為 HTTP 的 method 類型是有限的,但有一天,您可能想根據(jù)用戶 id 進行區(qū)分,類似這樣:
http_requests_total{method="POST",user_id="1"} http_requests_total{method="POST",user_id="2"} http_requests_total{method="POST",user_id="3"} […更多…] http_requests_total{method="POST",user_id="16434313"} http_requests_total{method="GET",user_id="1"} http_requests_total{method="GET",user_id="2"} http_requests_total{method="GET",user_id="3"} […更多…] http_requests_total{method="GET",user_id="16434313"} […更多…]
假設(shè)您有非常多的不同用戶,所以此時就存在嚴(yán)重的高基數(shù)問題,這將導(dǎo)致 Prometheus 內(nèi)存使用激增,直至 OOM。
所以請您牢記:指標(biāo)上標(biāo)簽的每一種唯一組合都會自動創(chuàng)建一個對應(yīng)時間序列,Prometheus 都會對其進行攝取、索引、存儲和處理。
雖然針對單個標(biāo)簽的不同值的數(shù)量沒有明確的限制,但因為不同值都是一個新的時間序列,您需要確保其數(shù)量保持在您 Prometheus 服務(wù)器容量之下(一個大型 Prometheus 單節(jié)點能夠處理數(shù)幾百萬個時間序列),所以你在設(shè)計時間序列的標(biāo)簽的時候,需要確保它們的所有組合總數(shù)在您 Prometheus 服務(wù)器可以承受的范圍內(nèi)。
對此,有一些標(biāo)簽值我們要特別注意避免,例如:
公網(wǎng) IP 或者郵件地址。
HTTP 請求 Path 全路徑,尤其這些路徑帶有動態(tài) ID 等信息。
進程ID(除非是有限集合)。
有時您想在不完全刪除標(biāo)簽的情況下解決標(biāo)簽高基數(shù)的問題,那么我們就要想辦法減少其值的基數(shù)。例如,對于 /api/users/739567637385/posts/28388445 的 HTTP 請求, 我們將動態(tài)信息部分使用 user_id 和 post_id 占位符統(tǒng)一替換,所以整個 path 可以替換為 /api/users/{user_id}/posts/{post_id} ,從而有效減少 path 標(biāo)簽的值數(shù)量。
錯誤 2:告警表達式中因聚合導(dǎo)致價值標(biāo)簽丟失
在做告警的時候,我們往往會通過聚合計算去除不關(guān)心的一些標(biāo)簽。例如,如果您想確定某個服務(wù)的總體錯誤率(跨所有標(biāo)簽維度)是否過高,您可以編寫如下規(guī)則:
sum(rate(errors_total{job="my-job"}[5m])) > 10
這看上去沒問題,但默認情況下,sum() 聚合器會去掉時序的所有標(biāo)簽。它不僅會刪除您想要聚合的維度(如實例、錯誤類型等),還會刪除一些比較通用的標(biāo)簽,這些標(biāo)簽對于 alertmanager 中進行告警的路由或靜默是有幫助的。特別是 job 標(biāo)簽,因為不同 job 通常由不同的運維團隊負責(zé)。因此我們應(yīng)該盡可能在聚合中保留此標(biāo)簽:sum by(job) (rate(errors_total{job=”my-job”}[5m])) > 10
一個更好的選擇是通過使用 without() 聚合修飾符替換 by() 聚合修飾符,從而顯示排除不想要的標(biāo)簽,而盡可能保留下一些你不確定需要刪除的標(biāo)簽:
sum without(instance, type) (rate(errors_total{job="my-job"}[5m])) > 10
這樣,聚合時您沒有明確指定刪除的標(biāo)簽在 Alertmanager 中仍然可以使用,這對于告警的聚合和路由非常有用,也能幫助您更好了解警報的來源。
錯誤 3:使用不帶任何限定范圍的(裸)選擇器
在編寫 PromQL 查詢(尤其是告警)的時候,我們需要格外小心,應(yīng)該從關(guān)心的業(yè)務(wù)或服務(wù)的數(shù)據(jù)中進行查詢,而不是全局范圍。因為不同的業(yè)務(wù)可能使用了相同的指標(biāo)名稱,它們甚至表達了不同的含義,隨著時間的推移,相同指標(biāo)名稱的服務(wù)會越來越多,這可能會完全影響您的告警規(guī)則或者儀表盤數(shù)據(jù)。
為避免不小心從不相關(guān)的任務(wù)或者服務(wù)中查詢數(shù)據(jù),我們一般使用 job 標(biāo)簽來限定選擇器的范圍,確保其查詢的數(shù)據(jù)都是您關(guān)心的業(yè)務(wù)或服務(wù)。
例如,以下查詢就是一個不安全的“裸”選擇器,它可能會從您不期望的其他 job 中選擇具有相同指標(biāo)名的數(shù)據(jù):
rate(errors_total[5m]) > 10
我們可以使用 {job=”my-job”} 的選擇器從而將指標(biāo)限定在 my-job 服務(wù)范圍:
rate(errors_total{job="my-job"}[5m]) > 10
這顯然是一個更安全的方式,它可以有效避免從無關(guān)服務(wù)中查詢數(shù)據(jù),對您告警產(chǎn)生干擾,也能大大提升查詢性能。
錯誤 4:告警規(guī)則沒有使用 for 字段
for 字段主要用于告警規(guī)則評估,它允許您能夠指定任意告警需要在連續(xù)的規(guī)則評估周期中出現(xiàn)多長時間才從 pending 狀態(tài)變?yōu)?firing。大多數(shù)告警規(guī)則可能我們可以忽略該字段,只需要兩個評估周期即可觸發(fā)告警,但有時,我們?yōu)榱伺懦秳拥母蓴_,比如一些 CPU 使用率,或者某個節(jié)點因為一兩次抓取異常就判定 down 了。
考慮一個警報規(guī)則,它使用 up 指標(biāo)來查找無法成功抓取的目標(biāo),并省略了可選的 for 修飾符:
alert: InstanceDownexpr: up == 0
一次失敗的抓?。ê苋菀装l(fā)生)將導(dǎo)致觸發(fā)此規(guī)則。通常你希望讓你的警報規(guī)則不那么容易觸發(fā),并至少等待幾分鐘,看看問題是否真的存在,然后再觸發(fā)通知:
alert: InstanceDownexpr: up == 0for: 5m # 一個實例只有真的掛掉或者無法訪問長達 5 分鐘才創(chuàng)建告警信息。
不帶 for 針對一些內(nèi)置的帶有平均數(shù)計算的查詢表達式也同樣有問題,例如表示高錯誤率的告警:
alert: HighErrorRateexpr: rate(my_errors_total{job="my-job"}[5m]) > 10
這個規(guī)則將在第一次查詢到最近 5m 中該錯誤數(shù)的平均值 > 10 就立即創(chuàng)建告警,雖然 5m 的平均周期能夠帶來一定的穩(wěn)健性,但是由于 Promtheus rate() 特性,我們考慮一下,一個完全新的服務(wù)或者一段時間未收集到數(shù)據(jù)會發(fā)生什么:
5 分鐘的 rate() 窗口只會考慮一些最近的樣本,實際上并不會對五分鐘的數(shù)據(jù)進行平均。
時間序列甚至根本還沒五分鐘數(shù)據(jù),該規(guī)則也可能會立即創(chuàng)建告警。
因此我們可以使用 for 修飾符來解決此問題:
alert: HighErrorRateexpr: rate(my_errors_total{job="my-job"}[5m]) > 10for: 5m
幾乎大多數(shù)的告警規(guī)則都可以添加此參數(shù),從而使使警報規(guī)則更加穩(wěn)健。但請記住,這也會導(dǎo)致警報的反應(yīng)時間變慢,因此找到這個平衡很重要。
錯誤 5:rate() 函數(shù)窗口時間太短
在太短的時間窗口內(nèi)計算速率時,您是否曾對間隙或完全空的圖表感到沮喪,例如 rate(my_counter[1m])?rate() 和其他 PromQL 函數(shù)(如 increase()、irate()、deriv())告訴您時間序列在給定時間窗口內(nèi)上升或下降的速度,在輸入時間窗口下至少需要兩個樣本,從而能夠告訴你這兩個樣本之間的序列是如何發(fā)展的。如果將時間窗口設(shè)置得太小,則在該窗口下可能只有一個或零個樣本,在這種情況下,輸出結(jié)果為空。
例如,如果您采用 20s 的時間窗口對一個 15s 抓取間隔的指標(biāo)進行 rate(),那么在這 20 秒時間窗口內(nèi)很可能不會涵蓋兩個樣本,因此您會得到一個與實際結(jié)果差異很大的比率:
采取極端的做法:如果將 rate 窗口縮小到 16s,當(dāng)兩個相距 15s 的點恰好落在任意對齊的 16s 窗口中時,您只會偶爾得到一個輸出點:
因此,您需要選擇一個足夠大的時間窗口——不僅僅是抓取間隔的 2 倍,因為您還需要面對偶爾抓取失敗和不幸的窗口對齊。所以通常我們選擇 rate 窗口大小至少為抓取間隔的 4 倍:
提示:使用 Grafana 時,可以使用 $__rate_interval 模板變量自動為您選擇一個安全間隔。
錯誤 6:rate() 相關(guān)函數(shù)用錯了指標(biāo)類型
查詢函數(shù)與指標(biāo)類型用錯的典型例子有:
rate() 函數(shù)用在 gauge 類型指標(biāo)
rate()、irate() 和 increase() 函數(shù)被設(shè)計成為僅適用于 counter 類型指標(biāo)。counter 類型是追蹤累計計數(shù)的指標(biāo),這些計數(shù)只會上升(永遠不會下降),除了在追蹤過程中偶爾因為重啟而重置為 0。為了在 rate 計算中盡可能消除計數(shù)器重置的影響,這些函數(shù)嘗試將提供的時間窗口內(nèi)樣本的值的任何減小都解釋為重置并對其進行補償。這種計數(shù)器的重置檢測和補償意味著您只能從這些函數(shù)中獲得正數(shù)的結(jié)果(或 0)。
如果你不小心傳入了一個可以自然上升和下降的指標(biāo)(比如內(nèi)存使用量),PromQL 將無法判斷這個錯誤,而只會返回一個不正確的輸出值。這是因為每次您的儀表指標(biāo)下降時,rate() 都會將其理解為計數(shù)器重置并且會錯誤地“糾正”它。
deriv() 函數(shù)用在 counter 類型指標(biāo)
您可以認為 deriv() 函數(shù)大致等同于 rate(),但它作用于 gauge 類型。deriv() 告訴您在輸入時間窗口內(nèi) gauge 類型指標(biāo)每秒上升或下降的速度。雖然并不常見,但這里與 rate() 相同的陷阱可能會給你帶來另外的困擾:因為 deriv() 函數(shù)沒有實現(xiàn)任何圍繞 counter 類型重置的邏輯(gauge 沒有這些),試圖使用 deriv() 計算一個在提供的窗口下有重置的 counter 的類型指標(biāo),就會得到一個不正確的結(jié)果,有時甚至是一個負數(shù)。
如何避免傳入錯誤類型的指標(biāo)?
由于 PromQL 無法自動檢測這種不正確的用法,所以您在使用這些函數(shù)時必須格外小心。我們除了經(jīng)驗和已有知識外,還可以依賴一些開源項目,例如 PromLens 查詢構(gòu)建器這樣的工具來輔助您檢測是否傳了錯誤的指標(biāo)類型:
結(jié)論
以上 6 點就是一些剛開始使用 Prometheus 的朋友經(jīng)常會犯的錯誤,希望這些技巧對您使用 Prometheus 的有所幫助!
鏈接:https://blog.51cto.com/u_15576159/8963563
本文翻譯自文章 https://promlabs.com/blog/2022/12/11/avoid-these-6-mistakes-when-getting-started-with-prometheus,感覺作者總結(jié)比較深刻,都是 Prometheus 新人們經(jīng)常犯的錯誤,故簡要翻譯一下,方便和大家一起審查與自省。
審核編輯:劉清
-
計數(shù)器
+關(guān)注
關(guān)注
32文章
2256瀏覽量
94561 -
HTTP
+關(guān)注
關(guān)注
0文章
505瀏覽量
31222 -
選擇器
+關(guān)注
關(guān)注
0文章
108瀏覽量
14539
原文標(biāo)題:Prometheus 新手常犯的 6 項錯誤,你該如何避免?
文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論