開源監控系統Prometheus的前世今生
Prometheus是SoundCloud公司開源的監控系統,同時也是繼Kubernetes之後,第二個加入CNCF的專案。Prometheus是一個優秀的監控系統,沃趣圍繞著Prometheus先後開發了多個元件,包括基礎告警元件,服務發現元件、各種採集的Exporters等,這些元件結合Prometheus支撐了沃趣大部分的監控業務。本文主要介紹Prometheus,從他的來源,架構以及一個具體的例子等方面來說明,以及沃趣圍繞Prometheus做了哪些工作。
起源
SoundCloud公司的之前的應用架構是巨石架構,也就是所有的功能放在一個大的模組裡,各個功能之間沒有明顯的界線。巨石架構的應用主要存在兩方面的問題,一方面在於很難對其進行水平擴充套件,只能垂直擴充套件,但是單臺機器的能力畢竟是有限的;另外一方面在於各個功能耦合在一塊,新增一個功能需要在已有的技術棧上進行開發,並且要確保不會對已有的功能造成影響。於是他們轉向了微服務架構,將原有的功能拆分成了幾百個獨立的服務,整個系統執行上千個例項。遷移到微服務架構給監控帶來一定的挑戰,現在不僅需要知道某個元件的執行的情況,還要知道服務的整體執行情況。他們當時的監控方案是:StatsD + Graphite + Nagios,StatsD結合Graphite構建監控圖表,各個服務將樣本資料推送給StatsD,StatsD將推送來的樣本資料聚合在一起,定時地推送給Graphite,Graphite將樣本資料儲存在時序資料庫中,使用者根據Graphite提供的API,結合自身監控的需求,構建監控圖表,通過圖表分析服務的指標(例如,延遲,每秒的請求數,每秒的錯誤數等)。
那麼這樣一種方案能滿足微服務架構對監控的要求麼?什麼要求呢:既能知道服務整體的執行情況,也能夠保持足夠的粒度,知道某個元件的執行情況。答案是很難,為什麼呢?例如,我們要統計api-server服務響應POST /tracks請求錯誤的數量,指標的名稱為api-server.tracks.post.500,這個指標可以通過http狀態碼來測量,服務響應的狀態碼為500就是錯誤的。Graphite指標名稱的結構是一種層次結構,api-server指定服務的名稱,tracks指定服務的handler,post指定請求的方法,500指定請求響應的狀態碼,api-server服務例項將該指標推送給StatsD,StatsD聚合各個例項推送來的指標,然後定時推送給Graphite。查詢api-server.tracks.post.500指標,我們能獲得服務錯誤的響應數,但是,如果我們的api-server服務跑了多個例項,想知道某個例項錯誤的響應數,該怎麼查詢呢?問題出在使用這樣一種架構,往往會將各個服務例項傳送來的指標聚合到一塊,聚合到一起之後,例項維度的資訊就丟失掉了,也就無法統計某個具體例項的指標資訊。
StatsD與Graphite的組合用來構建監控圖表,告警是另外一個系統-Nagios-來做的,這個系統執行檢測指令碼,判斷主機或服務執行的是否正常,如果不正常,傳送告警。Nagios最大的問題在於告警是面向主機的,每個告警的檢查項都是圍繞著主機的,在分散式系統的環境底下,主機down掉是正常的場景,服務本身的設計也是可以容忍節點down掉的,但是,這種場景下Nagios依然會觸發告警。
如果大家之前看過這篇
https://landing.google.com/sre ... arker
介紹Google Borgmon的文章,對比Prometheus,你會發現這兩個系統非常相似。實際上,Prometheus深受Borgmon系統的影響,並且當時參與構建Google監控系統的員工加入了SoundCloud公司。總之,種種因素的結合,促使了Prometheus系統的誕生。
Prometheus的解決方案
那麼,Prometheus是如何解決上面這些問題的?之前的方案中,告警與圖表的構建依賴於兩個不同的系統,Prometheus採取了一種新的模型,將採集時序資料作為整個系統的核心,無論是告警還是構建監控圖表,都是通過操縱時序資料來實現的。Prometheus通過指標的名稱以及label(key/value)的組合來識別時序資料,每個label代表一個維度,可以增加或者減少label來控制所選擇的時序資料,前面提到,微服務架構底下對監控的要求:既能知道服務整體的執行情況,也能夠保持足夠的粒度,知道某個元件的執行情況。藉助於這種多維度的資料模型可以很輕鬆的實現這個目標,還是拿之前那個統計http錯誤響應的例子來說明,我們這裡假設api_server服務有三個執行的例項,Prometheus採集到如下格式的樣本資料(其中intance label是Prometheus自動新增上去的):
如果我們只關心特定例項的錯誤數,只需新增instance label即可,例如我們想要檢視例項名稱為sample1的錯誤的請求數,那麼我就可以用api_server_http_requests_total{method="POST",handler="/tracks",status="500",instance="sample1"}這個表示式來選擇時序資料,選擇的資料如下:
如果我們關心整個服務的錯誤數,只需忽略instance label去除,然後將結果聚合到一塊,即可,例如
sum without(instance) (api_server_http_requests_total{method="POST",handler="/tracks",status="500"})計算得到的時序資料為:
告警是通過操縱時序資料而不是執行一個自定義的指令碼來實現的,因此,只要能夠採集到服務或主機暴露出的指標資料,那麼就可以告警。
架構
我們再來簡單的分析一下Prometheus的架構,看一下各個元件的功能,以及這些元件之間是如何互動的。
Prometheus Server是整個系統的核心,它定時地從監控目標(Exporters)暴露的API中拉取指標,然後將這些資料儲存到時序資料庫中,如果是監控目標是動態的,可以藉助服務發現的機制動態地新增這些監控目標,另外它還會暴露執行PromQL(用來操縱時序資料的語言)的API,其他元件,例如Prometheus Web,Grafana可以通過這個API查詢對應的時序資料。Prometheus Server會定時地執行告警規則,告警規則是PromQL表示式,表示式的值是true或false,如果是true,就將產生的告警資料推送給alertmanger。告警通知的聚合、分組、傳送、禁用、恢復等功能,並不是Prometheus Server來做的,而是Alertmanager來做的,Prometheus Server只是將觸發的告警資料推送給Alertmanager,然後Alertmanger根據配置將告警聚合到一塊,傳送給對應的接收人。
如果我們想要監控定時任務,想要instrument任務的執行時間,任務執行成功還是失敗,那麼如何將這些指標暴露給Prometheus Server?例如每隔一天做一次資料庫備份,我們想要知道每次備份執行了多長時間,備份是否成功,我們備份任務只會執行一段時間,如果備份任務結束了,Prometheus Server該如何拉取備份指標的資料呢?解決這種問題,可以通過Prometheus的pushgateway元件來做,每個備份任務將指標推送pushgateway元件,pushgateway將推送來的指標快取起來,Prometheus Server從Pushgateway中拉取指標。
例子
前面都是從比較大的層面——背景、架構——來介紹Prometheus,現在,讓我們從一個具體的例子出發,來看一下如何藉助Prometheus來構建監控圖表、分析系統效能以及告警。
我們有個服務,暴露出四個API,每個API只返回一些簡單的文字資料,現在,我們要對這個服務進行監控,希望藉助監控能夠檢視、分析服務的請求速率,請求的平均延遲以及請求的延遲分佈,並且當應用的延遲過高或者不可訪問時能夠觸發告警,程式碼示例如下:
我們按照instrumentation、exposition、collection、query這樣的流程構建監控系統,instrumentation關注的是如何測量應用的指標,有哪些指標需要測量;exposition關注的是如何通過http協議將指標暴露出來;collection關注的是如何採集指標;query關注的是如何構建查詢時序資料的PromQL表示式。我們首先從instrumentation這裡,有四個指標是我們關心的:
- 請求速率
- 請求的平均延遲
- 請求的延遲分佈
- 訪問狀態
首先將指標註冊進來,然後追蹤、記錄指標的值。用Prometheus提供的golang客戶端庫可以方便的追蹤、記錄指標的值,我們將instrumentation code放到應用的程式碼裡,每次請求,對應的指標狀態的值就會被記錄下來。
client golang提供了四種指標型別,分別為Counter, Gauge, Histogram, Summary,Counter型別的指標用來測量只會增加的值,例如服務的請求數;Gauge型別的指標用來測量狀態值,即可以變大,也可以變小的值,例如請求的延遲時間;Histogram與Summary指標類似,這兩個指標取樣觀察的值,記錄值的分佈,統計觀察值的數量,累計觀察到的值,可以用它來統計樣本資料的分佈。為了採集請求速率、平均延遲以及延遲分佈指標,方便起見用Histogram型別的指標追蹤、記錄每次請求的情況,Histogram型別的指標與普通型別(Counter、Gauge)不同的地方在於會生成多條樣本資料,一個是觀察樣本的總數,一個是觀察樣本值的累加值,另外是一系列的記錄樣本百分位數的樣本資料。訪問狀態可以使用up指標來表示,每次採集時,Prometheus會將採集的健康狀態記錄到up指標中。
instrumentation完成之後,下一步要做的就是exposition,只需將Prometheus http handler新增進來,指標就可以暴露出來。訪問這個Handler返回的樣本資料如下(省略了一些無關的樣本資料):
僅僅將指標暴露出來,並不能讓prometheus server來採集指標,我們需要進行第三步collection,配置prometheus server發現我們的服務,從而採集服務暴露出的樣本資料。我們簡單地看下prometheus server的配置,其中,global指定採集時全域性配置,
scrape_interval
指定採集的間隔,
evaluation_interval
指定
alerting rule
(alerting rule是PromQL表示式,值為布林型別,如果為true就將相關的告警通知推送給Alertmanager)也就是告警規則的求值時間間隔,scrape_timeout指定採集時的超時時間;alerting指定Alertmanager服務的地址;scrape_configs指定如何發現監控物件,其中job_name指定發現的服務屬於哪一類,static_configs指定服務靜態的地址,前面我們也提到,Prometheus支援動態服務發現,例如檔案、kubernetes服務發現機制,這裡我們使用最簡單的靜態服務發現機制。
採集完指標,就可以利用Prometheus提供的PromQL語言來操縱採集的時序資料,例如,我們想統計請求的平均速率,可以用這個表示式
irate(sample_app_latency_milliseconds_sum[1m]) / irate(sample_app_latency_milliseconds_count[1m])來計算。
有了時序資料之後,就可以藉助Grafana來構建監控圖表,具體怎麼配置Grafana圖表在這裡就不展開了,核心點是利用PromQL表示式選擇、計算時序資料。
Prometheus的告警是通過對Alerting Rule求值來實現的,alerting rule是一系列的PromQL表示式,alerting rule儲存在配置檔案中。我們想要對應用的延遲以及可用狀態進行告警,當應用過高或者不可訪問時就觸發告警,規則可以如下這樣定義:
其中UP指定服務的可用狀態,95th-latency指定95%的請求大於1000毫秒就觸發告警。Prometheus定時的對這些規則進行求值,如果條件滿足,就將告警通知傳送給Alertmanger,Alertmanger會根據自身路由配置,對告警進行聚合,分發到指定的接收人,我們想通過郵箱接收到告警,可以如下進行配置:
這樣,我們就可以通過郵箱收到告警郵件了。
相關的工作
無論是監控圖表相關的業務,還是告警相關的業務,都離不開相關指標的採集工作,沃趣是一家做資料庫產品的公司,我們花費了很多的精力去採集資料庫相關的指標,從Oracle到MySQL,再到SQL Server,主流的關係型資料庫的指標都有采集。對於一些通用的指標,例如作業系統相關的指標,我們主要是藉助開源的Exporters來採集的。沃趣的產品是軟、硬一體交付的,其中有大量硬體相關的指標需要採集,因此,我們也有專門採集硬體指標的Expoters。
沃趣大部分場景中,要監控的服務都是動態的。比如,使用者從平臺上申請了一個資料庫,需要增加相關的監控服務,使用者刪除資料庫資源,需要移除相關的監控服務,要監控的資料庫服務處於動態的變化之中。沃趣每個產品線的基礎架構都不相同,資料庫服務有跑在Oracle RAC上的,有跑在ZStack的,有跑在Kubernetes上的。對於跑在Kubernetes上的應用來說,並需要擔心Prometheus怎麼發現要監控的服務,只需要配置相關的服務發現的機制就可以了。對於其他型別的,我們主要藉助Prometheus的file_sd服務發現機制來實現,基於檔案的服務發現機制是一種最通用的機制,我們將要監控的物件寫到一個檔案中,Prometheus監聽這個檔案的變動,動態的維護要監控的物件,我們在file_sd基礎上構建了專門的元件去負責服務的動態更新,其他應用呼叫這個元件暴露的API來維護自身想要監控的物件。
Prometheus本身的機制的並不能滿足我們業務上對告警的要求,一方面我們需要對告警通知進行統計,但是Alertmanager本身並沒有對告警通知做持久化,服務重啟之後告警通知就丟失掉了;另外一方面使用者通過Web頁面來配置相關的告警,告警規則以及告警通知的路由需要根據使用者的配置動態的生成。為了解決這兩方面的問題,我們將相關的業務功能做成基礎的告警元件,供各個產品線去使用。針對Alertmanager不能持久化告警通知的問題,基礎告警元件利用Alertmanager webhook的機制來接收告警通知,然後將通知儲存到資料庫中;另外使用者的告警配置需要動態的生成,我們定義了一種新的模型來描述我們業務上的告警模型。
總結
Promtheus將採集時序資料作為整個系統的核心,無論是構建監控圖表還是告警,都是通過操縱時序資料來完成的。Prometheus藉助多維度的資料模型,以及強大的查詢語言滿足了微服務架構底下對監控的要求:既能知道服務整體的執行情況,也能夠保持足夠的粒度,知道某個元件的執行情況。沃趣站在巨人的肩旁上,圍繞Prometheus構建了自己的監控系統,從滿足不同採集要求的Exporters到服務發現,最後到基礎告警元件,這些元件結合Prometheus,構成了沃趣監控系統的核心。
作者:郭振,沃趣科技開發工程師,多年的Python、Golang等語言的開發經驗,熟悉Kubernetes、Prometheus等雲原生應用,負責QFusion RDS平臺以及基礎告警平臺的研發工作。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/28218939/viewspace-2658770/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 開源監控系統Prometheus介紹Prometheus
- 開源監控利器Prometheus初探Prometheus
- Prometheus監控報警系統Prometheus
- 對話系統的前世今生
- 序列推薦系統的前世今生
- 基於 Prometheus 的監控系統實踐Prometheus
- Prometheus監控系統入門與部署Prometheus
- Prometheus監控系統程序---process-exporterPrometheusExport
- 從零搭建Prometheus監控報警系統Prometheus
- 分散式系統:CAP 理論的前世今生分散式
- 恆生O32系統的前世今生
- .NET 開源實時監控系統 - WatchDog
- 使用Prometheus監控Linux系統各項指標PrometheusLinux指標
- Prometheus + InfluxDB + MySQL + Grafna快速構建監控系統PrometheusUXMySql
- docker-compose 搭建 Prometheus+Grafana監控系統DockerPrometheusGrafana
- 滴滴內部監控系統 Nightingale 開源啦
- docker-compose快速搭建 Prometheus+Grafana監控系統DockerPrometheusGrafana
- grafana+prometheus快速搭建MySql監控系統實踐GrafanaPrometheusMySql
- prometheus JVM監控PrometheusJVM
- Prometheus監控mongoPrometheusGo
- Prometheus 監控arangodbPrometheusGo
- 6.prometheus監控--監控dockerPrometheusDocker
- SSH Exporter:基於Prometheus的遠端系統效能監控神器ExportPrometheus
- Omi框架Store體系的前世今生框架
- RabbitMQ的前世今生MQ
- InfiniBand 的前世今生
- MySQL 的前世今生MySql
- Mybatis的前世今生MyBatis
- Unicode的前世今生Unicode
- Dubbo的前世今生
- Serverless 的前世今生Server
- IPD的前世今生
- CRM的前世今生
- DBHub的前世今生
- 搭建服務端效能監控系統 Prometheus 詳細指南服務端Prometheus
- WGCLOUD VS Prometheus :哪個監控系統更適合你GCCloudPrometheus
- 技術分享| 如何使用Prometheus實現系統程式監控Prometheus
- SpringBoot使用prometheus監控Spring BootPrometheus