Prometheus 是一個開源的監控解決方案,部署簡單易使用,難點在於如何設計符合特定需求的 Metrics 去全面高效地反映系統實時狀態,以助力故障問題的發現與定位。本文即基於最佳實踐的 Metrics 設計方法,結合具體的場景實例——TKE 的網絡組件 IPAMD 的內部監控,以我的實踐經驗談一談如何設計和實現適合的、可以更好反映系統實時狀態的監控指標(Metrics)。該篇內容適於 Prometheus 或相關監控系統的初學者(可無任何基礎瞭解),以及近期有 Prometheus 監控方案搭建和維護需求的系統開發管理者。經過這篇文章,能夠加深對 Prometheus Metrics 的理解,並能針對實際的監控場景提出更好的指標(Metrics)設計。node
Prometheus 是一個開源的監控解決方案,它可以提供監控指標數據的採集、存儲、查詢以及監控告警等功能。做爲雲原生基金會(CNCF)的畢業項目,Prometheus 已經在雲原生領域獲得了大範圍的應用,並逐漸成爲了業界最流行的監控解決方案之一。git
Prometheus 的部署和使用能夠說是簡單易上手,可是如何針對實際的問題和需求設計適宜的 Metrics 卻並非那麼直接可行,反而須要優先解決暴露出來的諸多不肯定問題,好比什麼時候選用 Vector,如何設計適宜的 buckets,Summary 和 Histogram 指標類型的取捨等。然而,要想有效助力故障及問題的發現與定位,必需要有一個合理有效的 Metrics 去全面高效地反映系統實時狀態。github
本文將介紹基於最佳實踐的 Metrics 設計方法,並結合具體的場景實例——TKE 的網絡組件 IPAMD 的內部監控,以我的實踐經驗談一談如何設計和實現適合的、可以更好反映系統實時狀態的監控指標(Metrics)。golang
本文以後的第 2 節將對 Prometheus 的 Metrics 作簡單的介紹,對此已有了解的讀者可跳過。以後第 3 節將介紹 Metrics 設計的最佳實踐。第 4 節將結合具體的實例應用相關設計方法。第 5 節將介紹 Golang 上指標收集的實現方案。web
Prometheus Metrics 是整個監控系統的核心,全部的監控指標數據都由其記錄。Prometheus 中,全部 Metrics 皆爲時序數據,並以名字做區分,即每一個指標收集到的樣本數據包含至少三個維度的信息:名字、時刻和數值。api
而 Prometheus Metrics 有四種基本的 type:緩存
此外,Prometheus Metrics 中有一種將樣本數據以標籤(Label)爲維度做切分的數據類型,稱爲向量(Vector)。四種基本類型也都有其 Vector 類型:性能優化
Vector 至關於一組同名同類型的 Metrics,以 Label 作區分。Label 能夠有多個,Prometheus 實際會爲每一個 Label 組合建立一個 Metric。Vector 類型記錄數據時需先打 Label 才能調用 Metrics 的方法記錄數據。服務器
如對於 HTTP 請求延遲這一指標,因爲 HTTP 請求可在多個地域的服務器處理,且具備不一樣的方法,因而,可定義名爲 http_request_latency_seconds
的 SummaryVec,標籤有region
和method
,以此表示不一樣地域服務器的不一樣請求方法的請求延遲。網絡
如下將對每一個類型作詳細的介紹。
方法:
type Counter interface { Metric Collector // 自增1 Inc() // 把給定值加入到計數器中. 若值小於 0 會 panic Add(float64)}
方法:
type Gauge interface { Metric Collector Set(float64) // 直接設置成給定值 Inc() // 自增1 Dec() // 自減1 Add(float64) // 增長給定值,可爲負 Sub(float64) // 減小給定值,可爲負 // SetToCurrentTime 將 Gauge 設置成當前的 Unix 時間戳 SetToCurrentTime()}
方法:
type Histogram interface { Metric Collector // Observe 將一個觀測到的樣本數據加入 Histogram 中,並更新相關信息 Observe(float64)}
inf 表無窮值,a1,a2,...是單調遞增的數值序列。
方法:
type Summary interface { Metric Collector // Observe 將一個觀測到的樣本數據加入 Summary 中,並更新相關信息 Observe(float64)}
實際分位數值可根據需求制定,且是對每個 Label 組合作聚合。
能夠看出,Histogram 和 Summary 類型測量的對象是比較接近的,但根據其實現方式和其自己的特色,在性能耗費、適用場景等方面具備必定差異,本文總結以下:
在具體設計 Metrics 以前,首先須要明確須要測量的對象。須要測量的對象應該依據具體的問題背景、需求和需監控的系統自己來肯定。
Google 針對大量分佈式監控的經驗總結出四個監控的黃金指標,這四個指標對於通常性的監控測量對象都具備較好的參考意義。這四個指標分別爲:
而筆者認爲,以上四種指標,實際上是爲了知足四個監控需求:
除了以上常規需求,還可根據具體的問題場景,爲了排除和發現之前出現過或可能出現的問題,肯定相應的測量對象。好比,系統須要常常調用的一個庫的接口可能耗時較長,或偶有失敗,可制定 Metrics 以測量這個接口的時延和失敗數。
另外一方面,爲了知足相應的需求,不一樣系統須要觀測的測量對象也是不一樣的。在 官方文檔 的最佳實踐中,將須要監控的應用分爲了三類:
對於每一類應用其一般狀況下測量的對象是不太同樣的。其總結以下:
除了系統自己,有時還需監控子系統:
最後的測量對象的肯定應結合以上兩點思路肯定。
選用 Vec 的原則:
例子:
此外,官方文檔 中建議,對於一個資源對象的不一樣操做,如 Read/Write、Send/Receive, 應採用不一樣的 Metric 去記錄,而不要放在一個 Metric 裏。緣由是監控時通常不會對這二者作聚合,而是分別去觀測。
不過對於 request 的測量,一般是以 Label 作區分不一樣的 action。
根據3.2,常見 Label 的選擇有:
肯定 Label 的一個重要原則是:同一維度 Label 的數據是可平均和可加和的,也即單位要統一。如風扇的風速和電壓就不能放在一個 Label 裏。
此外,不建議下列作法:
my_metric{label=a} 1my_metric{label=b} 6my_metric{label=total} 7
即在 Label 中同時統計了分和總的數據,建議採用 PromQL 在服務器端聚合獲得總和的結果。或者用另外的 Metric 去測量總的數據。
好的命名可以見名知義,所以命名也是良好設計的一環。
Metric 的命名:
Label 的命名:
根據前述 histogram 的統計原理可知,適宜的 buckets 能使 histogram 的百分位數計算更加準確。
理想狀況下,桶會使得數據分佈呈階梯狀,即各桶區間內數據個數大體相同。如圖1所示,是本人在實際場景下配置的buckets 數據直方圖,y 軸爲 buckets 內的數據個數,x 軸是各 buckets,能夠看出其近似成階梯狀。這種狀況下,當前桶個數下對數據的分辨率最大,各百分位數計算的準確率較高。
圖1 較爲理想的桶數據分佈
而根據筆者實踐經驗,爲了達成以上目標,buckets 的設計可聽從以下經驗:
該組件用於支持騰訊雲 TKE 的策略路由網絡方案。在這一網絡方案中,每一個 pod 的 IP 都是 VPC 子網的一個IP,且綁定到了所在節點的彈性網卡上,經過策略路由連通網絡,而且使得容器能夠支持騰訊雲的 VPC 的全部特性。
其中,在 2.0.0 版本之前,tke-eni-ipamd 組件是一個 IP 分配管理的 GRPC Server,其主要職責爲:
其工做原理和流程如圖 2 所示:
圖2 tke-eni-ipamd(v2.0.0-) 工做原理和流程
背景:
需求:
咱們的場景:
所以,須要如下幾類 Metric:
時延可選擇 Histogram 或 Summary 進行測量,如何選擇?
基於 2.5 節的二者對比,有以下分析:
Summary:
Histogram:
Summary 的缺點過於致命,難以迴避。Histogram 的缺點能夠經過增長工做量(即經過測試環境中的實驗來肯定各 Metrics 的大體分佈)和增長 Metrics(不用 Label 區分)來較好解決。
因此傾向於使用 Histogram。
詳細的 Metrics 規劃內容較多,這裏選取了一些表明性的樣例,列舉以下:
注1:DefBuckets指默認桶 ({.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10})。
注2:以上 buckets 持續微調中。
方案1:非侵入式裝飾器模式
樣例: kubelet/kuberuntime/instrumented_services.go
type instrumentedRuntimeService struct { service internalapi.RuntimeService}func recordOperation(operation string, start time.Time) { metrics.RuntimeOperations.WithLabelValues(operation).Inc() metrics.DeprecatedRuntimeOperations.WithLabelValues(operation).Inc() metrics.RuntimeOperationsDuration.WithLabelValues(operation).Observe(metrics.SinceInSeconds(start)) metrics.DeprecatedRuntimeOperationsLatency.WithLabelValues(operation).Observe(metrics.SinceInMicroseconds(start))}func (in instrumentedRuntimeService) Status() (*runtimeapi.RuntimeStatus, error) { const operation = "status" defer recordOperation(operation, time.Now()) out, err := in.service.Status() recordError(operation, err) return out, err}
優勢:
缺點:
方案2:defer 函數收集
樣例:
func test() (retErr error){ defer func(){ metrics.LatencySeconds.Observe(...) }() ... func body ...}
優勢:
缺點:
本文介紹了 Prometheus Metrics 及最佳實踐的 Metrics 設計和收集實現方法,並在具體的監控場景—— TKE 的網絡組件 IPAMD 的內部監控中應用了相關方法。
具體而言,本文基於最佳實踐,回答了 Prometheus Metrics 設計過程當中的若干問題:
此外,Metrics 設計並非一蹴而就的,需依據具體的需求的變化進行反覆迭代。好比需新增 Metrics 去發現定位可能出現的新問題和故障,再好比 Buckets 的設計也須要變化來適應測量數據分佈發生的變化,從而得到更精確的百分位數測量值。
【騰訊雲原生】雲說新品、雲研新術、雲遊新活、雲賞資訊,掃碼關注同名公衆號,及時獲取更多幹貨!!
![]()