如何使用 Prometheus 儀表化應(yīng)用
我們已經(jīng)知道了如何將應(yīng)用的監(jiān)控指標(biāo)如何接入 Prometheus,但是如何在自己的應(yīng)用程序中暴露監(jiān)控指標(biāo)呢?我們可以通過直接在應(yīng)用中集成 metrics 指標(biāo)數(shù)據(jù),也可以單獨(dú)開發(fā)一個對應(yīng)的 exporter 來暴露指標(biāo),或者根據(jù)需求編寫腳本推送到 pushgateway 網(wǎng)關(guān)生成監(jiān)控指標(biāo),不過最好的方式是直接在應(yīng)用程序中集成 Prometheus 監(jiān)控指標(biāo)數(shù)據(jù)。
接下來我們將來了解如何使用 Prometheus 客戶端庫來暴露監(jiān)控指標(biāo),使用一個 Prometheus Go 客戶端庫來儀表化一個 Go 應(yīng)用程序,直接在代碼中添加相關(guān)指標(biāo)以獲取對應(yīng)用程序的監(jiān)控能力。
抓取指標(biāo)
我們已經(jīng)很清楚 Prometheus 是如何抓取監(jiān)控指標(biāo)的了,Prometheus 通過一個 HTTP 請求抓取監(jiān)控目標(biāo),默認(rèn)請求的端點(diǎn)名是 /metrics。
監(jiān)控目標(biāo)通過發(fā)送每個被跟蹤的時間序列單個樣本,以及樣本的指標(biāo)名稱、標(biāo)簽集合和樣本值來響應(yīng)每個指標(biāo)的當(dāng)前狀態(tài)。抓取到數(shù)據(jù)后 Prometheus 會存儲每個樣本,并為其添加一個服務(wù)器端的時間戳,從而從單個抓取構(gòu)建成一組時間序列。
此外我們再回顧下獲取的監(jiān)控指標(biāo)格式:
- # HELP http_requests_total The total number of HTTP requests.
- # TYPE http_requests_total counter
- http_requests_total{method="post",code="200"} 1027
- http_requests_total{method="post",code="400"} 3
- # HELP process_open_fds Number of open file descriptors.
- # TYPE process_open_fds gauge
- process_open_fds 15
- # HELP http_request_duration_seconds A histogram of the request duration.
- # TYPE http_request_duration_seconds histogram
- http_request_duration_seconds_bucket{le="0.05"} 24054
- http_request_duration_seconds_bucket{le="0.1"} 33444
- http_request_duration_seconds_bucket{le="0.2"} 100392
- http_request_duration_seconds_bucket{le="0.5"} 129389
- http_request_duration_seconds_bucket{le="1"} 133988
- http_request_duration_seconds_bucket{le="+Inf"} 144320
- http_request_duration_seconds_sum 53423
- http_request_duration_seconds_count 144320
- # HELP rpc_duration_seconds A summary of RPC durations in seconds.
- # TYPE rpc_duration_seconds summary
- rpc_duration_seconds{quantile="0.01"} 3.102
- rpc_duration_seconds{quantile="0.05"} 3.272
- rpc_duration_seconds{quantile="0.5"} 4.773
- rpc_duration_seconds{quantile="0.9"} 9.001
- rpc_duration_seconds{quantile="0.99"} 76.656
- rpc_duration_seconds_sum 5.7560473e+04
- rpc_duration_seconds_count 2693
抓取目標(biāo)只會暴露當(dāng)前訪問的值,而不會暴露它所跟蹤數(shù)據(jù)所有的歷史指標(biāo),指標(biāo)中的每一行(注釋除外)就是一個時間序列的樣本,每個序列在同一個抓取中只能出現(xiàn)一次,所以,儀表化應(yīng)用只需要在內(nèi)存中跟蹤其指標(biāo)的當(dāng)前狀態(tài)即可,不需要跟蹤或緩存任何歷史指標(biāo)狀態(tài)。
客戶端庫
Prometheus 官方已經(jīng)提供了一些語言的客戶端庫,包括 Go、Java、Python、Ruby,還有一些非官方的第三方客戶端庫,可以用來幫助我們在應(yīng)用中集成 Prometheus 指標(biāo)服務(wù)。使用這些庫我們可以創(chuàng)建和跟蹤不同類型的指標(biāo),反映服務(wù)當(dāng)前的狀態(tài),這些庫都允許我們創(chuàng)建和更新單獨(dú)的指標(biāo)對象,將它們注冊到一個指標(biāo)注冊中心,然后通過 HTTP 暴露該指標(biāo)注冊中心,也就是我們常用的 metrics 接口。
Prometheus 的儀表化客戶端庫中包含不同的指標(biāo)類型:counters、gauges、histograms 以及 summaries,和 Prometheus 中的指標(biāo)類型對應(yīng),具體要使用哪種類型的指標(biāo)取決于我們的實(shí)際情況。
根據(jù)不同的指標(biāo)類型,在構(gòu)建指標(biāo)對象的時候需要提供不同的選項(xiàng),比如在創(chuàng)建直方圖的時候需要指定存儲桶 bucket,而創(chuàng)建計(jì)數(shù)器的時候下不需要其他額外參數(shù)的。此外構(gòu)造的指標(biāo)對象還為每種類型的指標(biāo)暴露了不同的狀態(tài)更新方法,例如,計(jì)數(shù)器具有增加當(dāng)前值的方法,但不會暴露將計(jì)數(shù)器設(shè)置為任意值的方法,但是儀表盤是允許我們設(shè)置當(dāng)前值的。
另外 Prometheus 的客戶端庫頁面(https://prometheus.io/docs/instrumenting/clientlibs/)上列出的所有官方庫的實(shí)現(xiàn)都考慮到了效率和并發(fā)安全問題:
- 效率:對指標(biāo)對象的狀態(tài)更新進(jìn)行了優(yōu)化
- 并發(fā)安全:指標(biāo)對象的所有狀態(tài)更新以及從指標(biāo)狀態(tài)讀取都是并發(fā)安全的,這意味著我們可以從多個線程(或 Go 中的 goroutines)更新指標(biāo)值,而無需考慮鎖的問題,你的應(yīng)用程序還能夠同時安全地處理多個指標(biāo)抓取。
所以我們是可以放心(當(dāng)然也是推薦)使用官方提供的客戶端庫來儀表化我們的應(yīng)用程序的。
跟蹤指標(biāo)當(dāng)對一個系統(tǒng)或者服務(wù)進(jìn)行儀表化的時候,盡量提供一些有意義的測量指標(biāo),業(yè)界有幾個比較著名的指導(dǎo)方針,可以幫助我們來理解在一個系統(tǒng)中應(yīng)該添加哪些指標(biāo)。
1.Google 的四大黃金指標(biāo)
有 4 個來自 Google SRE 手冊的黃金指標(biāo),這 4 個指標(biāo)主要針對應(yīng)用程序或用戶部分。
- 延遲(Latency):服務(wù)請求所需耗時,例如 HTTP 請求平均延遲。需要區(qū)分成功請求和失敗請求,因?yàn)槭≌埱罂赡軙苑浅5偷难舆t返回錯誤結(jié)果。
- 流量(Traffic):衡量服務(wù)容量需求(針對系統(tǒng)而言),例如每秒處理的 HTTP 請求數(shù)或者數(shù)據(jù)庫系統(tǒng)的事務(wù)數(shù)量。
- 錯誤(Errors):請求失敗的速率,用于衡量錯誤發(fā)生的情況,例如 HTTP500 錯誤數(shù)等顯式失敗,返回錯誤內(nèi)容或無效內(nèi)容等隱式失敗,以及由策略原因?qū)е碌氖?比如強(qiáng)制要求響應(yīng)時間超過 30ms 的請求為錯誤)。
- 飽和度(Saturation):衡量資源的使用情況,例如內(nèi)存、CPU、I/O、磁盤使用量(即將飽和的部分,比如正在快速填充的磁盤)。
2.資源指標(biāo)的 USE 方法
USE 是 Utilization(使用率)、Saturation(飽和度)、Error(錯誤)的首字母組合,是 Netflix 的內(nèi)核和性能工程師 Brendan Gregg 提出的,主要用于分析系統(tǒng)性能問題,可以指導(dǎo)用戶快速識別資源瓶頸及錯誤,主要可以考慮添加以下指標(biāo)。
- 使用率(Utilization):關(guān)注系統(tǒng)資源的使用情況,這里的資源主要包括但不限于 CPU、內(nèi)存、網(wǎng)絡(luò)、磁盤等,100%使用率通常是系統(tǒng)性能瓶頸的標(biāo)志。
- 飽和度(Saturation):例如調(diào)度器運(yùn)行隊(duì)列長度,這里主要是針對資源的飽和度(注意,不同于四大黃金指標(biāo))。任何資源在某種程度上的飽和都可能導(dǎo)致系統(tǒng)性能的下降。
- 錯誤(Errors):發(fā)生了多少(以及什么類型的)錯誤。例如,網(wǎng)卡在數(shù)據(jù)包傳輸過程中檢測到以太網(wǎng)絡(luò)沖突了 10 次。
3.請求服務(wù)系統(tǒng)的 RED 方法
RED 方法是 Weave Cloud 基于 Google 的 4 個黃金指標(biāo)再結(jié)合 Prometheus 及 Kubernetes 容器實(shí)踐得出的方法論,特別適用于對云原生應(yīng)用以及微服務(wù)架構(gòu)應(yīng)用進(jìn)行監(jiān)控和度量。在四大黃金指標(biāo)的原則下,RED 方法可以有效地幫助用戶衡量云原生以及微服務(wù)應(yīng)用下的用戶體驗(yàn)問題。RED 方法主要關(guān)注以下 3 種關(guān)鍵指標(biāo)。
- Request Counters:請求計(jì)數(shù)器。
- Errors Counters:錯誤計(jì)數(shù)器。
- Request Duration:每個請求所花費(fèi)的時間(histograms 或 summaries)。
一般來說,上述三大監(jiān)控理論的最佳實(shí)踐是:在遵循 Google 四大黃金指標(biāo)的前提下,對于在線系統(tǒng),結(jié)合 RED 方法和緩存命中率方式進(jìn)行監(jiān)測;對于離線系統(tǒng)或者主機(jī)監(jiān)控,以 USE 方法為主進(jìn)行監(jiān)測;對于批處理系統(tǒng),可以采用類似 Pushgateway 的形式進(jìn)行監(jiān)控。
當(dāng)然這些指南并不能完全覆蓋我們的實(shí)際監(jiān)控需求,但是對于我們在應(yīng)用中添加哪些指標(biāo)提供了一個很好的指導(dǎo)作用。Prometheus 官方文檔中關(guān)于儀表化的最佳實(shí)踐(https://prometheus.io/docs/practices/instrumentation/)提供了更多關(guān)于不同類型系統(tǒng)監(jiān)控的建議。
指標(biāo)命名
一個時間序列的指標(biāo)名稱描述了被監(jiān)測系統(tǒng)的某些狀態(tài),比如在如下所示的時間序列中:
- http_requests_total{job="nginx",instance="localhost:8080",method="POST"}
指標(biāo)名稱就是標(biāo)簽前面的 http_requests_total,該指標(biāo)名稱本身字面意思就可以幫助我們理解該指標(biāo)的含義了,雖然 Prometheus 本身并不會以語義方式解釋指標(biāo)名稱。為了幫助標(biāo)準(zhǔn)化指標(biāo)命名,Prometheus 官方文檔上列出了建議遵循的指標(biāo)命名最佳實(shí)踐(https://prometheus.io/docs/practices/naming/#metric-names)。
- 必須符合數(shù)據(jù)模型中的有效字符
- 必須有一個與指標(biāo)所屬領(lǐng)域相關(guān)的應(yīng)用前綴,這個前綴有時被客戶端庫成為命名空間,對于特定與某個應(yīng)用的指標(biāo),前綴通常是應(yīng)用名稱本身,當(dāng)然有時候指標(biāo)也是比較通用的,比如 prometheus_notifications_total 是特定于 Prometheus 應(yīng)用的指標(biāo),http_request_duration_seconds 用于所有的 HTTP 請求
- 必須有單一的單位,不要把秒和毫秒或字節(jié)這些混在一起
- 應(yīng)該使用基本的單位,比如秒、字節(jié)、米等
- 應(yīng)該有一個描述單位的后綴,采用復(fù)數(shù)形式,此外累積計(jì)數(shù)除了單位之外,還應(yīng)該有一個總數(shù) total 作為后綴,比如 http_reuqest_duration_seconds、node_memory_usage_bytes、http_requests_total (沒有單位的累計(jì)計(jì)數(shù))、process_cpu_seconds_total (帶單位的累計(jì)計(jì)數(shù))、foobar_build_info (用于提供關(guān)于運(yùn)行中的應(yīng)用元信息的指標(biāo))
請注意,直方圖和摘要還生成帶有后綴 _sum、_count 和 _bucket(單個直方圖桶的計(jì)數(shù)器)的計(jì)數(shù)器指標(biāo),但這些是根據(jù)基本指標(biāo)名稱自動生成的直方圖,因此我們不需要手動指定這些后綴。
一個給定指標(biāo)的所有維度上的 sum() 或 avg() 應(yīng)該是有意義的(盡管不一定有用),如果沒有意義,請將數(shù)據(jù)拆分為多個指標(biāo)。例如,將各種隊(duì)列的容量放在一個指標(biāo)中是可行的,而將一個隊(duì)列的容量與隊(duì)列中的當(dāng)前元素?cái)?shù)混合在一起則是不規(guī)范的。
標(biāo)簽
我們知道 Label 標(biāo)簽是 Prometheus 中非常重要的一個元素,在我們儀表化應(yīng)用的時候?yàn)橹笜?biāo)指定合適的標(biāo)簽也是非常重要的。我們知道每組唯一的標(biāo)簽(包括指標(biāo)名稱)都會標(biāo)識并自動創(chuàng)建一個唯一的時間序列,Prometheus 會在查詢期間跟蹤、存儲和處理該時間序列,時間序列的數(shù)量也是 Prometheus 主要的性能瓶頸之一,對于稍好性能的服務(wù)器來說,通??梢院芎玫奶幚韼装偃f的時間序列,當(dāng)然最好不要太大,所以在決定將哪些標(biāo)簽維度添加到指標(biāo)中的時候,需要考慮到這一點(diǎn)。
Prometheus 總的時間序列成本需要通過指標(biāo)上的不同標(biāo)簽維度相乘得到,比如我們按照 status code 和 method 來拆分 HTTP 請求計(jì)數(shù),則序列總數(shù)將是不同的 status code 和不同的 method 數(shù)量的乘積得到這兩個維度的所有有效組合,然后還需要將該基數(shù)乘以相同類型的受監(jiān)控目標(biāo)的數(shù)量,以得出 Prometheus 服務(wù)器的總體時間序列成本,所以對于標(biāo)簽維度的控制是非常重要的,不能太少,也不能太多。
為避免時間序列數(shù)量激增,請保持你的每個標(biāo)簽的可能值的數(shù)量有一定的限制。尤其要避免以下示例:
- 在一個標(biāo)簽值中存儲公共 IP 地址或電子郵件地址
- 在一個標(biāo)簽值中存儲完整的 HTTP 路徑,如果這些路徑包含 ID 或其他無限制的信息
- 或類似的模式
這將迅速產(chǎn)生一個不斷增加的時間系列,在短時間內(nèi)使 Prometheus 服務(wù)器過載,所以我們要避免用這種方式的標(biāo)簽值。接下來我們將學(xué)習(xí)使用 Prometheus 的 Go 客戶端庫(https://github.com/prometheus/client_golang)來為一個 Go 應(yīng)用程序添加和暴露監(jiān)控指標(biāo)。