本文首發于 vivo網際網路技術 微信公衆号
連結:
https://mp.weixin.qq.com/s/4NC4spF6cEvXuIBKVbIU7A 作者:ZhangShuo
Prometheus是繼Kubernetes(k8s)之後,CNCF畢業的第二個開源項目,其來源于Google的Borgmon。本文從“監控”這件事說起,深入淺出Prometheus的架構原理、目标發現、名額模型、聚合查詢等設計核心點。
一、前言
接觸過各式各樣的監控,開源的CAT、Zipkin、Pinpoint等等,并深度二次開發過;也接觸過收費的聽雲系APM,對各類監控的亮點與局限有足夠的了解。
去年10月我們快速落地了一套易用、靈活、有亮點的業務監控平台,其中使用到了Prometheus。從技術選型階段,Prometheus以及它的生态就讓我們印象深刻,今天就聊聊監控設計與Prometheus。
通常一個監控系統主要包含 采集(資訊源:log、metrics)、上報(協定:http、tcp)、聚合、存儲、可視化以及告警等等。其中采集上報主要是用戶端的核心功能,一般有定期外圍探測的(早期的Nagios、Zabbix)、AOP方式手動織入代碼的(埋點)、位元組碼自動織入等方式(無埋點)。
二、什麼是監控
一套産品化的,用來量化管理技術、業務的服務體系或解決方案。
這套産品主要解決兩個問題(産品價值):
- 技術:将系統的各種功能、狀态等技術表現資料化、可視化,來保證技術體系的穩定、安全等。
- 業務:将各種業務表現資料化、可視化,以供分析、及時幹預,保證業務高效開展。
三、監控的基礎原則
- 事前監控:架構設計階段務必需要考慮監控,而不是等到部署上線才去考慮
- 監控什麼:全局視角,自頂(業務)向下。對于一般業務來講,建議先監控離使用者最近的地方,使用者的良好體驗是推動業務發展的動力,這也是最敏感、重要的地方。

- 對使用者友好:監控服務易用,易接入,盡可能自動化
- 技術人員、業務人員的資訊源、能夠協助故障定位與解決
- 可視化:清晰的顯示各類資料(各類圖表展示),以及告警等資訊記錄
- 告警:
哪些問題需要通知?(如:需要人工幹預的,有意義的) 通知誰?(如:一線系統負責人) 如何通知?(如:短信、電話、其他通信工具;資訊清晰、準确、可操作) 多久通知一次?(如:5分鐘) 何時停止通知以及何時更新到其他人?(如:已恢複正常;兩個小時問題未恢複,更新通知到上級負責人)
四、Prometheus設計剖析
Prometheu聚焦于當下正在發生的各類資料,而不是追蹤數周以前的資料,因為他們認為“大多數監控查詢以及告警等都是一天内的資料”,
Facebook相關論文也驗證了這一點:85%的時序查詢是26小時之内的。
簡單來概括,Prometheus是一個準實時監控系統,并自帶時序資料能力。
1. 整體架構
Prometheus架構圖(引用自Prometheus官網)
簡化點的架構圖如下:
Prometheus 主要通過pull的方式擷取被監控程式(target\exports)中暴漏出來的時序資料。當然也提供了pushgateway服務,一般少量資料也可以push方式發送。
2. 目标發現
Prometheus通過pull的方式擷取服務的名額資料,那麼它是如何發現這些服務的呢?
可以通過多種方式來處理目标資源的發現:
2.1 人工的配置檔案清單
通過手工方式,添加靜态配置,指定需要監控的服務,如下target塊:
prometheus.yml
scrape_configs:
.....
#監控活動
- job_name: 'xxxxxxactivity-wap'
metrics_path: /prometheus/metrics
static_configs:
- targets: ['10.xx.xx.xx:8080',
...... ......]
#監控優惠券
- job_name: 'xxxxxxshop-coupon'
metrics_path: /prometheus/metrics
static_configs:
- targets: ['10.xx.xx.xx:8080',
...... ......]
#營銷
- job_name: 'xxxxxx-sales-api'
metrics_path: /prometheus/metrics
static_configs:
- targets: ['10.xx.xx.xx:8080',
...... ......
]
......
顯而易見,這種方式雖然很簡單,但是在繁忙的工作中持續維護一長串服務主機清單并不是一個可擴充的優雅方式,動态性、大規模會讓這種方式無法繼續下去。
指定加載目錄,這些目錄檔案的變更将通過磁盤監視檢測發現,然後Prometheus會立即應用這些變更。作為備用方案,檔案内容也将以指定的重新整理間隔(refresh_interval)定期被Prometheus重新讀取,發現變更後生效。
示例如下:
......
#監控 訂單中心OMS-API
scrape_configs:
- job_name: 'oms-api'
metrics_path: /prometheus/metrics
file_sd_configs:
- files:
- 'conf/oms-targets.json'
#預設 5分鐘
refresh_interval:5m
......
conf/oms-targets.json檔案(此檔案的變動将被監聽,通常這個檔案由另一個程式産生,如CMDB源):
oms-targets.json
[
{
"labels": {
"job": "oms-api"
},
"targets": [
'ip1:8080','ip2:8080',......
]
}
]
2.3 基于API的自動發現
目前可以用的本機服務發現插件有AmazonEC2、Azure、Consul、Kubernetes等等。
下文以Consul為例,執行個體啟動成功時可以通過腳本(或其他)方式将目前節點資訊,注冊到Consul上(類似啟動後向zk或redis寫入目前節點資訊)。Prometheus會實時的感覺到Consul資料的變動,并自動去做熱加載。
#監控 訂單中心OMS-API
- job_name: 'oms-api'
consul_sd_configs:
#consul 位址,預設監聽所有服務位址資訊
- server: 'xxxxxx'
services: []
注:Consul 是基于 GO 語言開發的開源工具,主要面向分布式,服務化的系統提供服務注冊、服務發現和配置管理的功能。Consul 提供服務注冊/發現、健康檢查、Key/Value存儲、多資料中心和分布式一緻性保證等功能
2.4 基于DNS的自動發現
在前幾種方式都不适合的情況下,DNS服務發現允許你指定DNS條目清單,然後查詢這些條目中的記錄,以發現擷取目标清單。用的比較少,不贅述。
被監控的目标成功被發現後,可以在自帶的web頁面上可視化檢視,如圖(本地模拟環境):
3. 名額收集與聚合
Prometheus通過pull的方式拉取外部程序中的時序資料名額(Exporter),拉取過程細節允許使用者配置相關資訊:如頻率、提前聚合規則、目标程序暴漏方式(http url)、如何連接配接、連接配接身份驗證等等。
名額
所謂名額就是軟體或硬體多種屬性的量化度量。有别于日志采集的那種ELK監控,Prometheus通過四種名額類型完成:
(1)測量型(Gauge):可增可減的數字(本質上是度量的快照)。常見的如記憶體使用率。
(2)計數型(counter):隻增不減,除非重置為0。比如某系統的HTTP請求量。
(3)直方圖(histogram):通過對監控的名額點進行抽樣,展示資料分布頻率情況的類型。
上圖強調了分布情況對于了解延遲等名額的重要性。如果我們假設這個名額的SLO(服務等級目标)為150ms,那麼137ms的平均延遲看起來是可以接受的;但實際上,每10個請求中就有1個在193ms以上完成,每100個請求中就有10個不達标!(如圖:90線、99線均不達标)
(4)摘要(summary):與Histogram非常類似,主要差別是summary在用戶端完成聚合,而Histogram在服務端完成。是以summary隻适合不需要集中聚合的單體名額(如GC相關名額)。
三條經驗法則:
- 如果需要多個采集節點的資料聚合、彙總,請選擇直方圖;
- 如果需要觀察多個采集節點資料的分布情況,請選擇直方圖;
- 如果不需要考慮叢集(如GC相關資訊),可選擇summary,它可以提供更加準确的分位數。
4. 聚合、查詢
内置的資料查詢DSL語言:PromQL,它可以快速的支援聚合和多種形式的查詢,并通過自帶的web界面,可以快速在浏覽器中查詢使用。在我們的實踐中,使用Grafana做可視化更加實用、美觀。
關于PromQL更多文法使用,可以檢視官網文檔,不贅述。
關于名額聚合
對于名額的聚合,Prometheus提供了多種函數。以下列聚合名額為例:
- 平均數
- 中間數
- 百分位數(如下圖99線:百分之99的請求要低于12s這個值)
- 标準差(衡量資料集差異情況,0代表與平均數一樣,越大表示資料差異越大)
- 變化率
5. 資料模型
Prometheus與其他主流時序資料庫一樣,在資料模型定義上,也會包含metric name、一個或多個labels(同InfluxDB裡的tags含義)以及metric value。
如用JSON表示一個時序資料庫中的原始時序資料:
一個json表示的時序資料示例
##用JSON表示一個時序資料
{
"timestamp": 1346846400, // 時間戳
"metric": "total_website_visits", // 名額名
"tags":{ // 标簽組
"instance": "aaa",
"job": "job001"
},
"value": 18 // 名額值
}
metric name加一組labels作為唯一辨別來定義time series(也就是時間線)。一旦label改變,則會建立新的時間序列,原有基于這個時間序列的配置将無效。在查詢時,支援根據labels條件查找time series,支援簡單的條件也支援複雜的條件。
上圖是所有資料點分布的一個簡單視圖,橫軸是時間,縱軸是時間線,區域内每個點就是資料點。Prometheus每次接收資料,收到的是圖中區域内縱向的一條線。這個表述很形象,因為在同一時刻,每條時間線隻會産生一個資料點,但同時會有多條時間線産生資料,把這些資料點連在一起,就是一條豎線。這個特征很重要,影響資料寫入和壓縮的優化政策。
保留時間
Prometheus專注于短期監控、告警而設計,是以預設它隻儲存15天的時間序列資料。如果要更長期,建議考慮資料單獨存儲到其他平台。目前我們的方案是遠端存儲,Prometheus拉取的資料會落到InfluxDB上,這樣保證了更好的存儲彈性,資料的實時落地存儲。
6.Prometheus開源生态
Prometheus生态系統包括了提供告警引擎、告警管理的AlertManager,支援push模式資料上報的PushGateWay,提供更優雅美觀的可視化界面的Grafana,支援遠端存儲的RemoteStoreAdapter;log轉換為metric的Mtail等等。
除此之外,還有一系列Exporter(可以了解為監控agent),這些Exporter可以直接安裝使用。自動監控應用程式、機器、主流資料庫、MQ等等。
Prometheus生态中還有一系列用戶端庫,支援各種主流程式設計語言Java、C、Python等等。
可以說Prometheus的生态是比較完善的,并且社群足夠活躍,未來可期。