分布式系統(tǒng)可觀測性之應用業(yè)務指標監(jiān)控
隨著分布式架構逐漸成為了架構設計的主流,可觀測性(Observability)一詞也日益被人頻繁地提起。
2017 年的分布式追蹤峰會(2017 Distributed Tracing Summit)結(jié)束后,Peter Bourgon 撰寫了總結(jié)文章《Metrics, Tracing, and Logging》系統(tǒng)地闡述了這三者的定義、特征,以及它們之間的關系與差異。文中將可觀測性問題映射到了如何處理指標(metrics)、追蹤(tracing)、日志(logging)三類數(shù)據(jù)上。
其后,Cindy Sridharan 在其著作《Distributed Systems Observability》中,進一步講到指標、追蹤、日志是可觀測性的三大支柱(three pillars)。
到了 2018 年, CNCF Landscape 率先出現(xiàn)了 Observability 的概念,將可觀測性( Observability )從控制論( Cybernetics )中引入到 IT 領域。在控制論中,可觀測性是指系統(tǒng)可以由其外部輸出,來推斷其內(nèi)部狀態(tài)的程度,系統(tǒng)的可觀察性越強,我們對系統(tǒng)的可控制性就越強。
可觀測性可以解決什么問題?Google SRE Book 第十二章給出了簡潔明快的答案:快速排障。
There are many ways to simplify and speed troubleshooting. Perhaps the most fundamental are:
- Building observability—with both white-box metrics and structured logs—into each component from the ground up
- Designing systems with well-understood and observable interfaces between components.
Google SRE Book, Chapter 12
而在云原生時代,分布式系統(tǒng)越來越復雜,分布式系統(tǒng)的變更是非常頻繁的,每次變更都可能導致新類型的故障。應用上線之后,如果缺少有效的監(jiān)控,很可能導致遇到問題我們自己都不知道,需要依靠用戶反饋才知道應用出了問題。
本文主要講述如何建立應用業(yè)務指標Metrics監(jiān)控和如何實現(xiàn)精準告警。Metrics 可以翻譯為度量或者指標,指的是對于一些關鍵信息以可聚合的、數(shù)值的形式做定期統(tǒng)計,并繪制出各種趨勢圖表。透過它,我們可以觀察系統(tǒng)的狀態(tài)與趨勢。
技術棧選擇
我們的應用都是 Spring Boot 應用,并且使用 Spring Boot Actuator 實現(xiàn)應用的健康檢查。從 Spring Boot 2.0 開始,Actuator 將底層改為 Micrometer,提供了更強、更靈活的監(jiān)測能力。Micrometer 支持對接各種監(jiān)控系統(tǒng),包括 Prometheus。
所以我們選擇 Micrometer 收集業(yè)務指標,Prometheus 進行指標的存儲和查詢,通過 Grafana 進行展示,通過阿里云的告警中心實現(xiàn)精準告警。
指標收集
對于整個研發(fā)部門來說,應該聚焦在能夠?qū)崟r體現(xiàn)公司業(yè)務狀態(tài)的最核心的指標上。例如 Amazon 和 eBay 會跟蹤銷售量, Google 和 Facebook 會跟蹤廣告曝光次數(shù)等與收入直接相關的實時指標。
Prometheus 默認采用一種名為 OpenMetrics 的指標協(xié)議。OpenMetrics 是一種基于文本的格式。下面是一個基于 OpenMetrics 格式的指標表示格式樣例。
指標的數(shù)據(jù)由指標名(metric_name),一組 key/value 標簽(label_name=label_value),數(shù)字類型的指標值(value),時間戳組成。
Meter
Micrometer 提供了多種度量類庫(Meter),Meter 是指一組用于收集應用中的度量數(shù)據(jù)的接口。Micrometer 中,Meter 的具體類型包括:Timer, Counter, Gauge, DistributionSummary, LongTaskTimer, FunctionCounter, FunctionTimer, and TimeGauge
- Counter 用來描述一個單調(diào)遞增的變量,如某個方法的調(diào)用次數(shù),緩存命中/訪問總次數(shù)等。支持配置 recordFailuresOnly,即只記錄方法調(diào)用失敗的次數(shù)。Counter 的指標數(shù)據(jù),默認有四個 label:class, method, exception, result。
- Timer 會同時記錄 totalcount, sumtime, maxtime 三種數(shù)據(jù),有一個默認的 label: exception。
- Gauge 用來描述在一個范圍內(nèi)持續(xù)波動的變量。Gauge 通常用于變動的測量值,比如隊列中的消息數(shù)量,線程池任務隊列數(shù)等。
- DistributionSummary 用于統(tǒng)計數(shù)據(jù)分布。
應用接入流程
為了方便微服務應用接入,我們封裝了
micrometer-spring-boot-starter。micrometer-spring-boot-starter 的具體實現(xiàn)如下。
1.入 Spring Boot Actuator 依賴
進行初始配置
Actuator 默認開啟了一些指標的收集,比如 system, jvm, http,可以通過配置關閉它們。其實僅僅是我們需要關閉,因為我們已經(jīng)接了 jmx exporter 了。
如果不希望 Web 應用的 Actuator 管理端口和應用端口重合的話,可以使用 management.server.port 設置獨立的端口。這是好的實踐,可以看到針對 actuator 的破壞,但是換了端口號,不暴露公網(wǎng)問題會少很多。
配置 spring bean
TimedAspect 的 Tags.empty() 是故意的,防止產(chǎn)生太長的 class 名稱對 prometheus 造成壓力。
應用接入時,引入
micrometer-spring-boot-starter 依賴
現(xiàn)在,就可以通過訪問
http://ip:port/actuator/prometheus,來查看 Micrometer 記錄的數(shù)據(jù)。
自定義業(yè)務指標
Micrometer 內(nèi)置了 Counted 和 Timed 兩個 annotation。可以通過在對應的方法上加上 @Timed 和 @Counted 注解,來收集方法的調(diào)用次數(shù),時間和是否發(fā)生異常等信息。
@Timed
如果想要記錄打印方法的調(diào)用次數(shù)和時間,需要給 print 方法加上 @Timed 注解,并給指標定義一個名稱。
在 print 方法上加上 @Timed 注解之后,Micrometer 會記錄 print 方法的調(diào)用次數(shù)(count),方法調(diào)用最大耗時(max),方法調(diào)用總耗時(sum)三個指標。percentiles = {0.95, 0.99} 表示計算 p95,p99 的請求時間。記錄的指標數(shù)據(jù)如下。
@Timed 注解支持配置一些屬性:
- value:必填,指標名
- extraTags:給指標定義標簽,支持多個,格式 {"key", "value", "key", "value"}
- percentiles:小于等于 1 的數(shù),計算時間的百分比分布,比如 p95,p99
- histogram:記錄方法耗時的 histogram 直方圖類型指標
@Timed 會記錄方法拋出的異常。不同的異常會被記錄為獨立的數(shù)據(jù)。代碼邏輯是先 catch 方法拋出的異常,記錄下異常名稱,然后再拋出方法本身的異常:
@Counted
如果不關心方法執(zhí)行的時間,只關心方法調(diào)用的次數(shù),甚至只關心方法調(diào)用發(fā)生異常的次數(shù),使用 @Counted 注解是更好的選擇。recordFailuresOnly = true 表示只記錄異常的方法調(diào)用次數(shù)。
記錄的指標數(shù)據(jù)如下。
counter 是一個遞增的數(shù)值,每次方法調(diào)用后,會自增 1。
Gauge
Gauge 用來描述在一個范圍內(nèi)持續(xù)波動的變量。Gauge 通常用于變動的測量值,例如雪花算法的 workId,打印的模板 id,線程池任務隊列數(shù)等。
- 注入 PrometheusMeterRegistry
- 構造 Gauge。給指標命名并賦值。
記錄的指標數(shù)據(jù)如下。
配置 SLA 指標
如果想要記錄指標時間數(shù)據(jù)的 sla 分布,Micrometer 提供了對應的配置:
記錄的指標數(shù)據(jù)如下。
存儲查詢
我們使用 Prometheus 進行指標數(shù)據(jù)的存儲和查詢。Prometheus 采用拉取式采集(Pull-Based Metrics Collection)。Pull 就是 Prometheus 主動從目標系統(tǒng)中拉取指標,相對地,Push 就是由目標系統(tǒng)主動推送指標。Prometheus 官方解釋選擇 Pull 的原因。
Pulling over HTTP offers a number of advantages:
- You can run your monitoring on your laptop when developing changes.
- You can more easily tell if a target is down.
- You can manually go to a target and inspect its health with a web browser.
Overall, we believe that pulling is slightly better than pushing, but it should not be considered a major point when considering a monitoring system.
Prometheus 也支持 Push 的采集方式,就是 Pushgateway。
For cases where you must push, we offer the Pushgateway.
為了讓 Prometheus 采集應用的指標數(shù)據(jù),我們需要做兩件事:
應用通過 service 暴露出 actuator 端口,并添加 label: monitor/metrics
添加 ServiceMonitor
Prometheus 會定時訪問 service 的 endpoints (
http://podip:port/manage/prometheusMetric),拉取應用的 metrics,保存到自己的時序數(shù)據(jù)庫。
Prometheus 存儲的數(shù)據(jù)是文本格式,雖然 Prometheus 也有 Graph,但是不夠炫酷,而且功能有限。還需要有一些可視化工具去展示數(shù)據(jù),通過標準易用的可視化大盤去獲知當前系統(tǒng)的運行狀態(tài)。比較常見的解決方案就是 Grafana。Prometheus 內(nèi)置了強大的時序數(shù)據(jù)庫,并提供了 PromQL 的數(shù)據(jù)查詢語言,能對時序數(shù)據(jù)進行豐富的查詢、聚合以及邏輯運算。通過在 Grafana 配置 Prometheus 數(shù)據(jù)源和 PromQL,讓 Grafana 去查詢 Prometheus 的指標數(shù)據(jù),以圖表的形式展示出來。
1. grafana 配置 Prometheus 數(shù)據(jù)源
2. 添加看板,配置數(shù)據(jù)源,query 語句,圖表樣式
3. 可以在一個 dasborad 添加多個看板,構成監(jiān)控大盤。
精準告警
任何系統(tǒng)都不是完美的,當出現(xiàn)異常和故障時,能在第一時間發(fā)現(xiàn)問題且快速定位問題原因就尤為重要。但要想做到以上這兩點,只有數(shù)據(jù)收集是不夠的,需要依賴完善的監(jiān)控和告警體系,迅速反應并發(fā)出告警。
我們最初的方案是,基于 Prometheus operator 的 PrometheusRule 創(chuàng)建告警規(guī)則, Prometheus servers 把告警發(fā)送給 Alertmanager,Alertmanager 負責把告警發(fā)到釘釘群機器人。但是這樣運行一段時間之后,我們發(fā)現(xiàn)這種方式存在一些問題。SRE 團隊和研發(fā)團隊負責人收到的告警太多,所有的告警都發(fā)到一個群里,打開群消息,滿屏的告警標題,告警級別,告警值。其中有需要運維處理的系統(tǒng)告警,有需要研發(fā)處理的應用告警,信息太多,很難快速篩選出高優(yōu)先級的告警,很難快速轉(zhuǎn)派告警到對應的處理人。所以我們希望應用告警可以精準發(fā)送到應用歸屬的研發(fā)團隊。
經(jīng)過一段時間的調(diào)研,我們最終選擇阿里云的《ARMS 告警運維中心》來負責告警的管理。ARMS 告警運維中心支持接入 Prometheus 數(shù)據(jù)源,支持添加釘釘群機器人作為聯(lián)系人。
1. 收集研發(fā)團隊的釘釘群機器人的 webhook 地址,創(chuàng)建機器人作為聯(lián)系人。
2. 給每個研發(fā)團隊分別配置通知策略,通知策略篩選告警信息里的 team 字段,并綁定對應的釘釘群機器人聯(lián)系人。
通過這個方式,實現(xiàn)了應用的告警直接發(fā)送到對應的研發(fā)團隊,節(jié)省了信息篩選和二次轉(zhuǎn)派的時間,提高了告警處理效率。
效果如下:
ARMS 告警運維中心支持接入 grafana,zabbix,arms 等多種數(shù)據(jù)源,具有告警分派和認領,告警匯總?cè)ブ?,通過升級通知方式對長時間沒有處理的告警進行多次提醒,或升級通知到領導,保證告警及時解決。
作者簡介:
趙君|南京愛福路汽車科技有限公司基礎設施部云原生工程師,過去一直從事 java 相關的架構和研發(fā)工作。目前主要負責公司的云原生落地相關工作,負責 F6 基礎設施和業(yè)務核心應用全面上云和云原生化改造。
徐航|南京愛福路汽車科技有限公司基礎設施部云原生工程師,過去一直負責數(shù)據(jù)庫高可用以及相關運維和調(diào)優(yōu)工作。目前主要負責研發(fā)效能 DevOps 的落地以及業(yè)務系統(tǒng)云原生可觀測性的改造。