指標(biāo)是用來衡量性能、消耗、效率和許多其他軟件屬性隨時間的變化趨勢。它們允許工程師通過警報和儀表盤來監(jiān)控一系列測量值的演變(如CPU或內(nèi)存使用量、請求持續(xù)時間、延遲等)。指標(biāo)在IT監(jiān)控領(lǐng)域有著悠久的歷史,并被工程師廣泛使用,與日志和鏈路追蹤一起被用來檢測系統(tǒng)是否有不符合預(yù)期的表現(xiàn)。 在其最基本的形式中,一個指標(biāo)數(shù)據(jù)點是由以下三個部分構(gòu)成:
一個指標(biāo)名稱
收集該數(shù)據(jù)點的時間戳
一個由數(shù)字表示的測量值
在過去的十年里,隨著系統(tǒng)變得越來越復(fù)雜,出現(xiàn)了維度度量的概念,也就是說,度量還包括一組標(biāo)簽或標(biāo)識(即維度),以提供額外的上下文。支持維度指標(biāo)的監(jiān)控系統(tǒng)允許工程師通過查詢特定的指標(biāo)名稱,并通過標(biāo)簽進行過濾和分組,從而輕易地在多個組件和維度上匯總和分析一個指標(biāo)。 Prometheus定義了一個度量說明格式和一個遠(yuǎn)程寫入?yún)f(xié)議,社區(qū)和許多供應(yīng)商都采用這個協(xié)議來說明和收集度量成為事實上的標(biāo)準(zhǔn)。OpenMetrics是另一個CNCF項目,它建立在Prometheus導(dǎo)出格式的基礎(chǔ)上,為收集度量標(biāo)準(zhǔn)提供了一個與廠商無關(guān)的標(biāo)準(zhǔn)化模型,旨在成為互聯(lián)網(wǎng)工程任務(wù)組(IEFT)的一部分。 最近,另一個CNCF項目OpenTelemetry出現(xiàn)了,它的目標(biāo)是提供一個新的標(biāo)準(zhǔn),能夠統(tǒng)一指標(biāo)、鏈路跟蹤和日志的收集,使跨領(lǐng)域的遙測信號收集和關(guān)聯(lián)更容易。 我們希望你在讀完這些文章后,你能理解每個標(biāo)準(zhǔn)之間的差異,這樣你就能決定哪一個能更好地滿足你當(dāng)前(和未來)的需求。
1、Prometheus指標(biāo)
首先要做的事。Prometheus收集的指標(biāo)有四種,作為其暴露格式的一部分。
Counters
Gauges
Histograms
Summaries
Prometheus 使用拉取模型來收集這些指標(biāo);也就是說,Prometheus 主動抓取暴露指標(biāo)的HTTP端點。這些端點可以是由被監(jiān)控的組件自然暴露,也可以通過社區(qū)建立的數(shù)百個Prometheus導(dǎo)出器之一暴露出來。Prometheus提供了不同編程語言的客戶端庫,你可以用它來監(jiān)控你的代碼。 由于服務(wù)發(fā)現(xiàn)機制和集群內(nèi)的共享網(wǎng)絡(luò)訪問,拉取模型在監(jiān)控 Kubernetes 集群時效果很好,但用 Prometheus 監(jiān)控動態(tài)的虛擬機集群、AWS Fargate 容器或 Lambda函數(shù)就比較困難了。 為什么呢?主要原因是交易確定要抓取的指標(biāo)端點,而且對這些端點的訪問可能受到網(wǎng)絡(luò)安全策略的限制。為了解決其中的一些問題,社區(qū)在2021年底發(fā)布了Prometheus Agent Mode,它只收集指標(biāo)并使用遠(yuǎn)程寫入?yún)f(xié)議將其發(fā)送到監(jiān)控后端。
Prometheus 可以抓取 Prometheus 暴露格式和 OpenMetrics 格式的指標(biāo)。在這兩種情況下,指標(biāo)通過HTTP接口暴露,使用簡單的基于文本的格式(更常用和廣泛支持)或更有效和強大的 Protobuf 格式。文本格式的一大優(yōu)勢是它的可讀性,這意味著你可以在瀏覽器中打開它或使用像curl這樣的工具來檢索當(dāng)前暴露的指標(biāo)集。 Prometheus 使用一個非常簡單的指標(biāo)模型,有四種指標(biāo)類型,只在客戶端SDK中支持。所有的指標(biāo)類型都是用一種數(shù)據(jù)類型或由多個單一數(shù)據(jù)類型的組合在暴露格式中表示。這個數(shù)據(jù)類型包括一個指標(biāo)名稱、一組標(biāo)簽和一個浮點數(shù)。時間戳是由監(jiān)控后端(例如 Prometheus)或代理在抓取指標(biāo)時添加的。 指標(biāo)名稱和標(biāo)簽集的每個唯一組合定義了一條時間序列,而每個時間戳和浮點數(shù)定義了一個系列中的樣本(即一個數(shù)據(jù)點)。 一些慣例被用來表示不同的度量類型。 Prometheus暴露格式的一個非常有用的特點是能夠?qū)⒃獢?shù)據(jù)與度量相關(guān)聯(lián),以定義其類型并提供描述。例如,Prometheus提供了這些信息,Grafana利用這些信息向用戶顯示額外的上下文信息,幫助他們選擇正確的度量并應(yīng)用正確的PromQL函數(shù)。
# HELP用來為指標(biāo)提供描述,# TYPE為指標(biāo)提供類型。
現(xiàn)在,讓我們來更詳細(xì)地介紹一下每個Prometheus指標(biāo)類型。
計數(shù)器(Counter)
Counter類型指標(biāo)被用于單調(diào)增加的測量結(jié)果。因此它們總是累積的數(shù)值,值只能上升。唯一的例外是 Counter 重啟,在這種情況下,它的值會被重置為零。 Counter 的實際值通常本身并不十分有用。一個計數(shù)器的值經(jīng)常被用來計算兩個時間戳之間的 delta 或者隨時間變化的速率。 例如,Counter 的一個典型用例是記錄API調(diào)用次數(shù),這是一個總是會增加的測量值。
# HELP http_requests_total Total number of http api requests # TYPE http_requests_total counter http_requests_total{api="add_product"} 4633433
指標(biāo)名稱是http_requests_total,它有一個名為api的標(biāo)簽,值為add_product,Counter 的值為 4633433。
這意味著自從上次服務(wù)啟動或Counter重置以來,add_product的 API 已經(jīng)被調(diào)用了 4633433 次。按照慣例,Counter 類型的指標(biāo)通常以_total為后綴。
這個絕對數(shù)字并沒有給我們提供多少信息,但當(dāng)與 PromQL 的 rate 函數(shù)(或其他監(jiān)控后端的類似函數(shù))一起使用時,它可以幫助我們了解該API每秒收到的請求數(shù)。下面的 PromQL 查詢計算了過去5分鐘內(nèi)每秒的平均請求數(shù)。
rate(http_requests_total{api="add_product"}[5m])為了計算一段時期內(nèi)的絕對變化,我們將使用 delta 函數(shù),在 PromQL 中稱為increate():
increase(http_requests_total{api="add_product"}[5m])
這將返回過去5分鐘內(nèi)的總請求數(shù),這相當(dāng)于用每秒的速率乘以間隔時間的秒數(shù)(在我們的例子中是5分鐘):
rate(http_requests_total{api="add_product"}[5m]) * 5 * 60
其他你可能會使用 Counter 類型指標(biāo)的例子:測量電子商務(wù)網(wǎng)站的訂單數(shù)量,在網(wǎng)絡(luò)接口上發(fā)送和接收的字節(jié)數(shù),或者應(yīng)用程序中的錯誤數(shù)量。如果它是一個會一直上升的指標(biāo),那么就使用一個Counter。
下面是一個例子,說明如何使用 Prometheus 客戶端庫在 Python 中創(chuàng)建和增加一個計數(shù)器指標(biāo):
from prometheus_client import Counter api_requests_counter = Counter( 'http_requests_total', 'Total number of http api requests', ['api'] ) api_requests_counter.labels(api='add_product').inc()
需要注意的是,由于Counter可以被重置為零,你要確保你用來存儲和查詢指標(biāo)的后端能夠支持這種情況,并且在Counter重啟的情況下仍然提供準(zhǔn)確的結(jié)果。
Prometheus 和兼容 PromQL 的 Prometheus 遠(yuǎn)程存儲系統(tǒng),如 Promscale,可以正確處理 Counter 重啟。
儀表(Gauge)
Gauge 指標(biāo)用于可以任意增加或減少的測量。這是你可能更熟悉的指標(biāo)類型,因為即使沒有經(jīng)過額外處理的實際值也是有意義的,它們經(jīng)常被使用到。例如,測量溫度、CPU和內(nèi)存使用的指標(biāo),或者隊列的大小都是Gauge。
例如,為了測量一臺主機的內(nèi)存使用情況,我們可以使用一個Gauge指標(biāo),比如:
# HELP node_memory_used_bytes Total memory used in the node in bytes # TYPE node_memory_used_bytes gauge node_memory_used_bytes{hostname="host1.domain.com"} 943348382上面的指標(biāo)表明,在測量時,節(jié)點 host1.domain.com 使用的內(nèi)存約為 900 MB。該指標(biāo)的值是有意義的,不需要任何額外的計算,因為它告訴我們該節(jié)點上消耗了多少內(nèi)存。 與使用?Counter?指標(biāo)時不同,rate和delta函數(shù)對Gauge沒有意義。然而,計算特定時間序列的平均數(shù)、最大值、最小值或百分比的函數(shù)經(jīng)常與 Gauge一起使用。 在 Prometheus 中,這些函數(shù)的名稱是avg_over_time、max_over_time、min_over_time和quantile_over_time。要計算過去10分鐘內(nèi)在host1.domain.com 上使用的平均內(nèi)存,你可以這樣做:
avg_over_time(node_memory_used_bytes{hostname="host1.domain.com"}[10m])要使用 Prometheus 客戶端庫在 Python 中創(chuàng)建一個 Gauge 指標(biāo),你可以這樣做:
from prometheus_client import Gauge memory_used = Gauge( 'node_memory_used_bytes', 'Total memory used in the node in bytes', ['hostname'] ) memory_used.labels(hostname='host1.domain.com').set(943348382)
直方圖(Histogram)
Histogram 指標(biāo)對于表示測量的分布很有用。它們經(jīng)常被用來測量請求持續(xù)時間或響應(yīng)大小。 直方圖將整個測量范圍劃分為一組區(qū)間,稱為桶,并計算每個桶中有多少測量值。 一個直方圖指標(biāo)包括幾個項目:
一個包含測量次數(shù)的Counter。指標(biāo)名稱使用_count后綴。
一個包含所有測量值之和的Counter。指標(biāo)名稱使用_sum后綴。
直方圖桶被暴露為一系列的Counter,使用指標(biāo)名稱的后綴_bucket和表示桶的上限的le label。Prometheus中的桶是包含桶的邊界的,即一個上限為N的桶(即le label)包括所有數(shù)值小于或等于N的數(shù)據(jù)點。
例如,測量運行在 host1.domain.com 實例上的 add_productAPI 端點實例的響應(yīng)時間的 Histogram 指標(biāo)可以表示為:
# HELP http_request_duration_seconds Api requests response time in seconds # TYPE http_request_duration_seconds histogram http_request_duration_seconds_sum{api="add_product" instance="host1.domain.com"} 8953.332 http_request_duration_seconds_count{api="add_product" instance="host1.domain.com"} 27892 http_request_duration_seconds_bucket{api="add_product" instance="host1.domain.com" le="0"} http_request_duration_seconds_bucket{api="add_product", instance="host1.domain.com", le="0.01"} 0 http_request_duration_seconds_bucket{api="add_product", instance="host1.domain.com", le="0.025"} 8 http_request_duration_seconds_bucket{api="add_product", instance="host1.domain.com", le="0.05"} 1672 http_request_duration_seconds_bucket{api="add_product", instance="host1.domain.com", le="0.1"} 8954 http_request_duration_seconds_bucket{api="add_product", instance="host1.domain.com", le="0.25"} 14251 http_request_duration_seconds_bucket{api="add_product", instance="host1.domain.com", le="0.5"} 24101 http_request_duration_seconds_bucket{api="add_product", instance="host1.domain.com", le="1"} 26351 http_request_duration_seconds_bucket{api="add_product", instance="host1.domain.com", le="2.5"} 27534 http_request_duration_seconds_bucket{api="add_product", instance="host1.domain.com", le="5"} 27814 http_request_duration_seconds_bucket{api="add_product", instance="host1.domain.com", le="10"} 27881 http_request_duration_seconds_bucket{api="add_product", instance="host1.domain.com", le="25"} 27890 http_request_duration_seconds_bucket{api="add_product", instance="host1.domain.com", le="+Inf"} 27892上面的例子包括sum、counter和12個桶。sum和counter可以用來計算一個測量值隨時間變化的平均值。在PromQL中,過去5分鐘的平均請求響應(yīng)時間可以通過如下方式計算得到。
rate(http_request_duration_seconds_sum{api=”add_product”, instance=”host1.domain.com”}[5m]) / rate(http_request_duration_seconds_count{api=”add_product”, instance=”host1.domain.com”}[5m])它也可以被用來計算各時間序列的平均數(shù)。下面的 PromQL 查詢將計算出所有API和實例在過去5分鐘內(nèi)的平均請求響應(yīng)時間。
sum(rate(http_request_duration_seconds_sum[5m])) / sum(rate(http_request_duration_seconds_count[5m]))
利用 Histogram,你可以在查詢時計算單個時間序列以及多個時間序列的百分位。在PromQL中,我們將使用histogram_quantile函數(shù)。Prometheus使用分位數(shù)而不是百分位數(shù)。
它們本質(zhì)上是一樣的,但是以0到1的比例表示的,而百分位數(shù)是以0到100的比例表示的。要計算在host1.domain.com上運行的add_product API響應(yīng)時間的第99百分位數(shù)(0.99四分位數(shù)),你可以使用以下查詢。
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket{api=”add_product”, instance=”host1.domain.com”}[5m]))
Histograms 的一大優(yōu)勢是可以進行匯總。下面的查詢返回所有API和實例的響應(yīng)時間的第99個百分點?:
histogram_quantile(0.99, sum by (le) (rate(http_request_duration_seconds_bucket[5m])))
在云原生環(huán)境中,通常有許多相同組件的多個實例在運行,能否跨實例匯總數(shù)據(jù)是關(guān)鍵。 Histograms有三個主要的缺點:首先,桶必須是預(yù)定義的,這需要一些前期的設(shè)計。如果你的桶沒有被很好地定義,你可能無法計算出你需要的百分比,或者會消耗不必要的資源。例如,如果你有一個總是需要超過一秒鐘的API,那么擁有上限(le label)小于一秒鐘的桶將是無用的,只會消耗監(jiān)控后端服務(wù)器的計算和存儲資源。另一方面,如果99.9%的API請求耗時少于50毫秒,那么擁有一個上限為100毫秒的初始桶將無法讓你準(zhǔn)確測量API的性能。
第二,他們提供的是近似的百分位數(shù),而不是精確的百分位數(shù)。這通常沒什么問題,只要你的桶被設(shè)計為提供具有合理準(zhǔn)確性的結(jié)果。
第三,由于百分位數(shù)需要在服務(wù)器端計算,當(dāng)有大量數(shù)據(jù)需要處理時,它們的計算成本會非常高。在Prometheus中減輕這種情況的一個方法是使用錄制規(guī)則來預(yù)先計算所需的百分位數(shù)。
下面的例子顯示了如何使用 Prometheus 的 Python 客戶端庫創(chuàng)建一個帶有自定義桶的直方圖指標(biāo)。
from prometheus_client import Histogram api_request_duration = Histogram( name='http_request_duration_seconds', documentation='Api requests response time in seconds', labelnames=['api', 'instance'], buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 25 ) ) api_request_duration.labels( api='add_product', instance='host1.domain.com' ).observe(0.3672)匯總(Summary)
像直方圖一樣,Summary指標(biāo)對于測量請求持續(xù)時間和響應(yīng)體大小很有用。
像直方圖一樣,匯總度量對于測量請求持續(xù)時間和響應(yīng)大小很有用。
一個Summary指標(biāo)包括這些指標(biāo):
一個包含總測量次數(shù)的Counter。指標(biāo)名稱使用_count后綴。
一個包含所有測量值之和的Counter。指標(biāo)名稱使用_sum后綴??梢赃x擇使用帶有分位數(shù)標(biāo)簽的指標(biāo)名稱,來暴露一些測量值的分位數(shù)指標(biāo)。由于你不希望這些量值是從應(yīng)用程序運行的整個時間內(nèi)測得的,Prometheus客戶端庫通常會使用流式的分位值,這些分位值是在一個滑動的(通常是可配置的)時間窗口上計算得到的。
例如,測量在 host1.domain.com 上運行的 add_productAPI 端點實例的響應(yīng)時間的 Summary 指標(biāo)可以表示為:
# HELP http_request_duration_seconds Api requests response time in seconds # TYPE http_request_duration_seconds summary http_request_duration_seconds_sum{api="add_product" instance="host1.domain.com"} 8953.332 http_request_duration_seconds_count{api="add_product" instance="host1.domain.com"} 27892 http_request_duration_seconds{api="add_product" instance="host1.domain.com" quantile="0"} http_request_duration_seconds{api="add_product" instance="host1.domain.com" quantile="0.5"} 0.232227334 http_request_duration_seconds{api="add_product" instance="host1.domain.com" quantile="0.90"} 0.821139321 http_request_duration_seconds{api="add_product" instance="host1.domain.com" quantile="0.95"} 1.528948804 http_request_duration_seconds{api="add_product" instance="host1.domain.com" quantile="0.99"} 2.829188272 http_request_duration_seconds{api="add_product" instance="host1.domain.com" quantile="1"} 34.283829292上面這個例子包括總和和計數(shù)以及五個分位數(shù)。分位數(shù)0相當(dāng)于最小值,分位數(shù)1相當(dāng)于最大值。分位數(shù)0.5是中位數(shù),分位數(shù)0.90、0.95和0.99相當(dāng)于在host1.domain.com上運行的add_product API端點響應(yīng)時間的第90、95和99個百分位。 像直方圖一樣,Summary指標(biāo)包括總和和計數(shù),可用于計算隨時間的平均值以及不同時間序列的平均值。 Summary提供了比Histogram更精確的百分位計算結(jié)果,但這些百分位有三個主要缺點
首先,客戶端計算百分位是很昂貴的。這是因為客戶端庫必須保持一個有序的數(shù)據(jù)點列表,以進行這種計算。在Prometheus SDK中的實現(xiàn)限制了內(nèi)存中保留和排序的數(shù)據(jù)點的數(shù)量,這降低了準(zhǔn)確性以換取效率的提高。注意,并非所有的Prometheus客戶端庫都支持匯總指標(biāo)中的量值。例如,Python SDK就不支持。
第二,你要查詢的量值必須由客戶端預(yù)先定義。只有那些已經(jīng)提供了指標(biāo)的量值才能通過查詢返回。沒有辦法在查詢時計算其他百分位。增加一個新的百分位指標(biāo)需要修改代碼,該指標(biāo)才可以被使用。
第三,也是最重要的一點,不可能把多個Summary指標(biāo)進行聚合計算。這使得它們對動態(tài)現(xiàn)代系統(tǒng)中的大多數(shù)用例毫無用處,在這些用例中,通常我們對一個特定的組件感興趣,這個視角是全局的,它不與特定的實例關(guān)聯(lián)。
因此,想象一下,在我們的例子中,add_product 的 API 端點運行在10個主機上,在這些服務(wù)之前有一個負(fù)載均衡器。我們沒有任何聚合函數(shù)可以用來計算add_product API 接口在所有請求中響應(yīng)時間的第99百分位數(shù),無論這些請求被發(fā)送到哪個后端實例上。我們只能看到每個主機的第99個百分點。 同樣地,我們也只能知道某個接口,比如 add_productAPI 端點的(在某個實例上的)第99百分位數(shù),而不能對不同的接口進行聚合。
下面的代碼使用 Prometheus 的 Python 客戶端庫創(chuàng)建了一個 Summary 指標(biāo)。
from prometheus_client import Summary api_request_duration = Summary( 'http_request_duration_seconds', 'Api requests response time in seconds', ['api', 'instance'] ) api_request_duration.labels(api='add_product', instance='host1.domain.com').observe(0.3672)
上面的代碼沒有定義任何量化指標(biāo),只會產(chǎn)生總和和計數(shù)指標(biāo)。Prometheus 的Python SDK 不支持 Summary 指標(biāo)中的分位數(shù)計算。
Histogram還是Summary? 在大多數(shù)情況下,直方圖是首選,因為它更靈活,并允許匯總百分位數(shù)。 在不需要百分位數(shù)而只需要平均數(shù)的情況下,或者在需要非常精確的百分位數(shù)的情況下,匯總是有用的。例如,在履行關(guān)鍵系統(tǒng)的合約責(zé)任的情況下。 下表總結(jié)了直方圖和匯總表的優(yōu)點和缺點。
編輯:黃飛
?
評論