手把手教你實(shí)現(xiàn)SpringBoot微服務(wù)監(jiān)控!
你知道的越多,不知道的就越多,業(yè)余的像一棵小草!
你來,我們一起精進(jìn)!你不來,我和你的競爭對手一起精進(jìn)!
編輯:業(yè)余草
juejin.cn/post/7056817945787236389
推薦:https://www.xttblog.com/?p=5311
SpringBoot 微服務(wù)監(jiān)控
?使用 Micrometer、Prometheus 和 Grafana 為 Spring Boot 微服務(wù)構(gòu)建全面的監(jiān)控能力
?
介紹
在使用微服務(wù)和事件驅(qū)動架構(gòu)(EDA)時(shí),監(jiān)控、日志、追蹤和告警等方面的可觀察性是一個(gè)架構(gòu)十分重要的關(guān)注點(diǎn),主要是因?yàn)椋?/p>
大規(guī)模的部署需要集中且自動化的監(jiān)控與可觀測能力
架構(gòu)的異步性和分布式性質(zhì)使得關(guān)聯(lián)多個(gè)組件產(chǎn)生的指標(biāo)變得困難
解決這個(gè)架構(gòu)問題可以簡化架構(gòu)管理,并加快解決運(yùn)行時(shí)問題的周轉(zhuǎn)時(shí)間。還能提供有助于做出明智的架構(gòu)、設(shè)計(jì)、部署和基礎(chǔ)設(shè)施的見解,,以改善平臺的非功能特性。此外,自定義指標(biāo)的產(chǎn)出、收集和可視化可以為業(yè)務(wù)或運(yùn)營帶來其他有用的信息。
然而在實(shí)際的架構(gòu)應(yīng)用中,這個(gè)問題經(jīng)常被忽略。本教程通過使用 Micrometer、Prometheus 和 Grafana 等開源工具對 Java 和 Spring Boot 微服務(wù)的可觀察性進(jìn)行監(jiān)控,相信會成為該方面最佳的實(shí)踐指南。
先決條件
在你開始本教程之前,你需要設(shè)置以下環(huán)境:
擁有 Docker Compose: https://docs.docker.com/compose/;工具的 Docker:https://www.docker.com/環(huán)境一個(gè)用于克隆和編輯 git repo 中的代碼的 Java IDE
預(yù)計(jì)時(shí)間
完成本教程大約需要 2 個(gè)小時(shí)。
監(jiān)控概述
監(jiān)控工具的主要目標(biāo)是:
監(jiān)控應(yīng)用程序性能 為利益相關(guān)者(開發(fā)團(tuán)隊(duì)、基礎(chǔ)架構(gòu)團(tuán)隊(duì)、運(yùn)營用戶、維護(hù)團(tuán)隊(duì)和商業(yè)用戶)提供自助服務(wù)。 協(xié)助進(jìn)行快速問題溯源分析(RCA) 建立應(yīng)用程序的性能基線 如果使用云服務(wù),提供云服務(wù)使用成本的監(jiān)測能力,并以集成的方式監(jiān)控不同的云服務(wù)
監(jiān)控主要體現(xiàn)在以下四類行為:
應(yīng)用的 「指標(biāo)化」 ——對應(yīng)用進(jìn)行指標(biāo)化帶來的指標(biāo)度量對監(jiān)控應(yīng)用和維護(hù)團(tuán)隊(duì)以及業(yè)務(wù)用戶十分重要。有許多非侵入性的方法來度量指標(biāo),最流行的是“字節(jié)碼檢測”、“面向切面的編程”和“JMX”。 「指標(biāo)收集」 —— 從應(yīng)用中收集指標(biāo),并將其持久化到相應(yīng)的存儲庫中。然后,存儲庫需要提供一種查詢和匯總數(shù)據(jù)的方法,以實(shí)現(xiàn)數(shù)據(jù)的可視化。市面上流行的收集器有 Prometheus、StatsD 和 DataDaog。大多數(shù)指標(biāo)收集工具是時(shí)間序列存儲庫,并提供高級查詢能力。 「指標(biāo)可視化」 —— 可視化工具指標(biāo)查詢庫,建立視圖和儀表盤供最終用戶使用。它們提供豐富的用戶界面來對指標(biāo)執(zhí)行各種操作,例如聚合、數(shù)據(jù)下探等。 「告警和通知」 —— 當(dāng)指標(biāo)超過定義的閾值(例如 CPU 超過 80% 且持續(xù) 10 分鐘),可能需要人工干預(yù)。為此,告警和通知很重要。大多數(shù)可視化工具提供了告警和通知能力。
許多開源和商業(yè)產(chǎn)品可用于監(jiān)控。一些著名的商業(yè)產(chǎn)品有:AppDynamics、Dynatrace、DataDog、logdna 和 sysdig。開源工具通常被組合使用。一些非常流行的組合是 Prometheus 和 Grafana、Elastic-Logstash-Kibana (ELK) 和 StatsD + Graphite。
微服務(wù)監(jiān)控指南
我們鼓勵在所有微服務(wù)中將收集的指標(biāo)類型保持一致。這有助于提高監(jiān)控儀表盤的復(fù)用性,并簡化指標(biāo)的聚合和下探(drill-down),以便在不同層面上對其進(jìn)行可視化。
要監(jiān)控什么
微服務(wù)暴露一個(gè) API 和(或)消費(fèi)事件和消息。在處理過程中,它可能會調(diào)用自己的業(yè)務(wù)組件,例如連接到數(shù)據(jù)庫,調(diào)用技術(shù)服務(wù)(緩存、審核等),調(diào)用其他微服務(wù)和(或)發(fā)送事件和消息。在這些不同的處理階段監(jiān)測指標(biāo)是有益的,因?yàn)樗兄谔峁╆P(guān)于性能和異常情況的匯總分析。這反過來又有助于快速分析問題。
與事件驅(qū)動架構(gòu)(EDA)和微服務(wù)相關(guān)的常用指標(biāo)包括:
「資源利用率指標(biāo)」
資源利用率 —— CPU、內(nèi)存、磁盤利用率、網(wǎng)絡(luò)利用率等
JVM 堆和 GC 指標(biāo) —— GC 開銷、GC 時(shí)間、堆(及其不同區(qū)域)利用率
JVM 線程利用率 —— 阻塞、可運(yùn)行、等待連接使用時(shí)間
「應(yīng)用程序指標(biāo)」
微服務(wù)不同架構(gòu)層的可用性、延遲、吞吐量、狀態(tài)、異常等,例如:
控制器層 —— 用于 HTTP/REST 方法調(diào)用
服務(wù)層——用于方法調(diào)用
數(shù)據(jù)訪問層——用于方法調(diào)用
集成層——用于 RPC 調(diào)用、HTTP/REST/API 調(diào)用、消息發(fā)布、消息消費(fèi)
「技術(shù)服務(wù)利用率指標(biāo)」 (具體到對應(yīng)的技術(shù)服務(wù))
緩存——緩存的命中率、丟失率、寫入率、清理率、讀取率 日志——每個(gè)日志級別的日志事件數(shù) 連接池——連接池的使用率、連接等待時(shí)間、連接創(chuàng)建時(shí)間、空閑置連接數(shù) 「中間件指標(biāo)」
事件代理(Event broker)指標(biāo)——可用性、消息吞吐、字節(jié)吞吐、消費(fèi)滯后、(反)序列化異常、集群狀態(tài) 數(shù)據(jù)庫指標(biāo)
對于應(yīng)用指標(biāo),理想情況下,微服務(wù)中每個(gè)架構(gòu)層的入口和出口點(diǎn)都應(yīng)該被檢測。
微服務(wù)的關(guān)鍵指標(biāo)特征
在監(jiān)控微服務(wù)時(shí),指標(biāo)的以下三個(gè)特征很重要:
維度 時(shí)間序列/速率匯總 指標(biāo)觀點(diǎn)
維度
維度控制了一個(gè)指標(biāo)的聚合方式,以及特定指標(biāo)的深入程度。它是通過向一個(gè)指標(biāo)添加標(biāo)簽來實(shí)現(xiàn)的。標(biāo)簽是一組鍵值對信息(如 name-value )。標(biāo)簽被用來限定通過對監(jiān)控系統(tǒng)的查詢來獲取或聚合指標(biāo)。由于大量的部署,它是監(jiān)控微服務(wù)的重要特征。換句話說,多個(gè)微服務(wù)(甚至一個(gè)微服務(wù)的不同組件)會發(fā)送同名的指標(biāo)。為了區(qū)分它們,你需用維度來限定指標(biāo)。
例如,對于 http_server_requests_seconds_count 這個(gè)指標(biāo)。如果有多個(gè) API 節(jié)點(diǎn)(在微服務(wù)生態(tài)中就是如此),那么在沒有維度的情況下,就只能在平臺層面查看這個(gè)指標(biāo)的聚合值。無法獲得該指標(biāo)在不同 API 節(jié)點(diǎn)分布的具體情況。在發(fā)送指標(biāo)的時(shí)候,給指標(biāo)添加一個(gè) uri 標(biāo)簽,就可以獲取對應(yīng)的分布??纯聪旅娴睦?,它解釋了這個(gè)特性。
如果 http_server_requests_seconds_count 使用以下標(biāo)簽產(chǎn)出指標(biāo)數(shù)據(jù):
http_server_requests_seconds_count{appName="samplemicrosvc",env="local",exception="None",instanceId="1",method="GET",outcome="SUCCESS",status="200",uri="/addressDetails/{addressId}",} 67.0
http_server_requests_seconds_count{appName="samplemicrosvc",env="local",exception="InternalServerError",instanceId="1",method="GET",outcome="SERVER_ERROR",status="500",uri="/userInfo/{userId}",} 39.0
http_server_requests_seconds_count{appName="samplemicrosvc",env="local",exception="None",instanceId="1",method="GET",outcome="SUCCESS",status="200",uri="/userInfo/{userId}",} 67.0
http_server_requests_seconds_count{appName="samplemicrosvc",env="local",exception="IllegalArgumentException",instanceId="1",method="GET",outcome="SERVER_ERROR",status="500",uri="/addressDetails/{addressId}",} 13.0
http_server_requests_seconds_count{appName="samplemicrosvc",env="local",exception="IllegalStateException",instanceId="1",method="GET",outcome="SERVER_ERROR",status="500",uri="/addressDetails/{addressId}",} 26.0
那么通過 HTTP 響應(yīng)狀態(tài)或結(jié)果即可將 http_server_requests_seconds_count 指標(biāo)在 appName 級別、instanceId 級別下聚合,查詢語句如下:
# Count distribution by status for a given environment
sum by (status) (http_server_requests_seconds_count{env="$env"})
# Count distribution by uri and status for a given environment
sum by (uri, status) (http_server_requests_seconds_count{env="$env"})
# Count distribution by uri, status and appName for a given environment
sum by (uri, status, appName) (http_server_requests_seconds_count{env="$env"})
標(biāo)簽也可以用作查詢條件。請注意 env 標(biāo)簽的用法,其中 $env 是 Grafana 儀表板用于用戶輸入“環(huán)境”的變量。
時(shí)間序列/速率聚合
隨時(shí)間聚合指標(biāo)的能力對于應(yīng)用的性能分析非常重要,例如將性能與負(fù)載模式相關(guān)聯(lián),構(gòu)建天/周/月的性能配置文件,以及創(chuàng)建應(yīng)用程序的性能基線。
指標(biāo)視角
這是一個(gè)派生的特征,并提供了將度量組合在一起以便于可視化和使用的能力。例如:
描述平臺所有微服務(wù)可用性狀態(tài)的儀表盤 每個(gè)微服務(wù)的下探(詳細(xì))視圖,用于查看微服務(wù)的詳細(xì)指標(biāo) 中間件組件的集群視圖和詳細(xì)視圖,例如 Event Broker
檢測 Spring Boot 微服務(wù)
本節(jié)介紹微服務(wù)及其 REST 控制器、服務(wù) bean、組件 bean 和數(shù)據(jù)訪問對象的檢測。本文還介紹了與 EDA 或集成相關(guān)的一些組件,例如 kafka 中的生產(chǎn)者與消費(fèi)者,spring-cloud-stream 或 Apache Camel 中的 camel 路由。
為了幫助微服務(wù)的監(jiān)控和管理,這里我們使用了 Spring Boot Actuator:https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html#production-ready服務(wù)。這是一個(gè)開箱即用的、使用多個(gè) HTTP 和 JMX 節(jié)點(diǎn)來監(jiān)控應(yīng)用程序的第三方組件,可以實(shí)現(xiàn)對微服務(wù)的健康狀況、bean 信息、應(yīng)用程序信息和環(huán)境信息的基本監(jiān)控。
為了啟用該功能,我們需要將 spring-boot-starter-actuator 添加為應(yīng)用的依賴:
<dependency>
????<groupId>org.springframework.bootgroupId>
????<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
開箱即用的 Actuator 指標(biāo)
將 Spring Boot Actuator 添加到微服務(wù)后,以下指標(biāo)可以被直接使用:
JVM 指標(biāo)(與 GC 和線程利用率相關(guān)) 資源利用率指標(biāo)(CPU、線程、文件描述符、JVM 堆和垃圾收集指標(biāo)) Kafka 消費(fèi)者指標(biāo) 日志指標(biāo)(Log4j2、Logback) 可用性指標(biāo)(進(jìn)程正常運(yùn)行時(shí)間) 緩存指標(biāo)(Caffeine、EhCache2、Hazelcast 或任何符合 JSR-107 的緩存) Tomcat 指標(biāo) Spring 集成指標(biāo)
自定義指標(biāo)節(jié)點(diǎn)
Actuator 還為指標(biāo)創(chuàng)建自定義節(jié)點(diǎn)。默認(rèn)情況下,它存儲在 /actuator/metrics 中。需要通過 Spring 配置暴露出來。以下是示例配置:
management:
??endpoints:
????web:
??????exposure:
????????include:
??????????[
????????????"health",
????????????"info",
????????????"metrics",
????????????"prometheus",
????????????"bindings",
????????????"beans",
????????????"env",
????????????"loggers",
????????????"streamsbindings",
??????????]
Micrometer
為了與度量工具集成,Spring Boot Actuator 為 Micrometer:https://micrometer.io/ 提供了自動配置。Micrometer 為包括 Prometheus 在內(nèi)的大量監(jiān)控系統(tǒng)提供了一個(gè)外觀。本教程假定你對 Micrometer 的概念https://micrometer.io/docs/concepts有一定的了解。Micrometer 提供了三種收集指標(biāo)的機(jī)制:
計(jì)數(shù)器(Counter)——通常用于計(jì)數(shù)出現(xiàn)、方法執(zhí)行、異常等 計(jì)時(shí)器(Timer)——用于測量持續(xù)時(shí)間和發(fā)生次數(shù);通常用于測量延遲 量規(guī)(Gauge)——單點(diǎn)時(shí)間度量;例如,線程數(shù)
與 Prometheus 集成
由于 Prometheus 使用輪詢的方式來收集指標(biāo),因此集成 Prometheus 和 Micrometer 是相對簡單的兩步過程。
添加 micrometer-registry-prometheus注冊。聲明一個(gè) MeterRegistryCustomizer類型的 bean。
這是一個(gè)可選操作。但是,我推薦你這樣做,因?yàn)樗峁┝艘环N自定義 MeterRegistry。這對通過 Micrometer 收集的指標(biāo)數(shù)據(jù)而聲明的通用標(biāo)簽(維度)很有用。尤其是當(dāng)有很多微服務(wù)或每個(gè)微服務(wù)有多個(gè)實(shí)例時(shí),這樣做有助于數(shù)據(jù)指標(biāo)的下探,常用的標(biāo)記通常包括 applicationName、instanceName 和 environment。這允許你跨應(yīng)用與實(shí)例來構(gòu)建聚合數(shù)據(jù)的可視化,并能夠深入到特定的實(shí)例、應(yīng)用程序或環(huán)境。
配置完成后,Actuator 將暴露一個(gè) /actuator/prometheus 中配置的節(jié)點(diǎn) ,該端點(diǎn)應(yīng)在 Spring 配置中啟用。然后我們需要在 Prometheus 中配置一個(gè) job,以便以指定的頻率獲取該節(jié)點(diǎn)產(chǎn)出的數(shù)據(jù)。
將 Prometheus 依賴添加到 pom
<dependency>
????<groupId>io.micrometergroupId>
????<artifactId>micrometer-registry-prometheusartifactId>
dependency>
自定義 MetricsRegistry
利用 MetricsRegistryCustomizer 聲明的配置類可以作為框架的一部分,以便所有微服務(wù)實(shí)現(xiàn)都可以復(fù)用它。可以使用系統(tǒng)/應(yīng)用屬性作為標(biāo)簽。
@Configuration
public?class?MicroSvcMeterRegistryConfig?{
????@Value("${spring.application.name}")
????String?appName;
????@Value("${env}")
????String?environment;
????@Value("${instanceId}")
????String?instanceId;
????@Bean
????MeterRegistryCustomizer?configureMetricsRegistry()
???? {
????????return?registry?->?registry.config().commonTags("appName",?appName,?"env",?environment,?"instanceId",?instanceId);
????}
應(yīng)用程序級別指標(biāo)的檢測
一些應(yīng)用程序級別的指標(biāo)是開箱即用的,在某些情況下,可以采用多種指標(biāo)。下表總結(jié)了這些功能:
| 指標(biāo) | 控制器 | 服務(wù)層組件 | 數(shù)據(jù)訪問對象 | 業(yè)務(wù)組件 | 技術(shù)組件 | Kafka 消費(fèi)者 | Kafka 生產(chǎn)者 | Spring 集成組件 | HTTP 客戶端 | Camel 路由 |
|---|---|---|---|---|---|---|---|---|---|---|
| 「資源利用率」(CPU、線程、文件描述符、堆、GC) | 開箱即用的微服務(wù)實(shí)例級別 | |||||||||
| 「可用性」 | 開箱即用的微服務(wù)實(shí)例級別 | |||||||||
| 「延遲」 | 開箱即用的@Timed注釋 | 通過 Spring-AOP 的自定義可重用方面完成 | 通過 Spring-AOP 的自定義可重用方面完成 | 通過 Spring-AOP 的自定義可重用方面完成 | 開箱即用的日志記錄、緩存和 JDBC 連接池 | 如果使用 spring-cloud-stream,則開箱即用 | 通過自定義 MeterBinder bean 完成 | 開箱即用 | 開箱即用 | 提供部分支持。需要自定義路線儀表。 |
| 「吞吐量」 | 開箱即用的@Timed注釋 | 通過 Spring-AOP 的自定義可重用方面完成 | 通過 Spring-AOP 的自定義可重用方面完成 | 通過 Spring-AOP 的自定義可重用方面完成 | 開箱即用的日志記錄、緩存和 JDBC 連接池 | 如果使用 spring-cloud-stream,則開箱即用 | 通過自定義 MeterBinder bean 完成 | 開箱即用 | 開箱即用 | 提供部分支持。需要自定義路線儀表。 |
| 「例外」 | 開箱即用的@Timed注釋 | 通過 Spring-AOP 的自定義可重用方面完成 | 通過 Spring-AOP 的自定義可重用方面完成 | 通過 Spring-AOP 的自定義可重用方面完成 | 開箱即用的日志記錄、緩存和 JDBC 連接池 | 如果使用 spring-cloud-stream,則開箱即用 | 通過自定義 MeterBinder bean 完成 | 開箱即用 | 開箱即用 | 提供部分支持。需要自定義路線儀表。 |
檢測 REST 服務(wù)的控制器
檢測 REST 控制器的最快、最簡單的方法是使用 @Timed 注解標(biāo)記在控制器或控制器的各個(gè)方法上。@Timed 注解自動添加 exception、method、 outcome、status和 uri 標(biāo)簽到定時(shí)器。@Timed 注解也可以添加額外的標(biāo)簽。
檢測微服務(wù)的不同架構(gòu)層
微服務(wù)通常具有控制器層(Controller)、服務(wù)層(Service)、數(shù)據(jù)訪問層(DAO)和集成層(Integration)。添加了 @Timed 注解的控制器層通常不需要任何額外的檢測,而對于服務(wù)層、數(shù)據(jù)訪問層和集成層,開發(fā)人員通常會使用@Service 或者 @Component 注解創(chuàng)建自定義的 bean。與延遲、吞吐量和異常相關(guān)的指標(biāo)可以為系統(tǒng)分析提供重要的信息。這些可以很容易地使用 Micrometer 的 Timer 和 Counter 來收集。但是,需要對代碼進(jìn)行檢測才能應(yīng)用這些指標(biāo)。這時(shí)就需要使用 spring-aop 創(chuàng)建檢測服務(wù)和組件的復(fù)用類,以便于在所有的微服務(wù)中使用。使用 @Around 和@AfterThrowing 注解則可以無需向服務(wù)/組件的類和方法添加任何代碼生成建議指標(biāo)。以下是參考指南:
創(chuàng)建可復(fù)用的注解以應(yīng)用于不同類型的組件/服務(wù)。例如
@MonitoredService、@MonitoredDAO和@MonitoredIntegrationComponent這樣的自定義注解,分別添加到服務(wù),數(shù)據(jù)訪問對象,和集成組件上。定義多個(gè)切點(diǎn)來為不同類型的組件應(yīng)用建議,并且這些組件包含上述注解。
將適當(dāng)?shù)臉?biāo)簽應(yīng)用于指標(biāo),以便可以對指標(biāo)進(jìn)行深入分析或切片。例如,可以使用
componentClass、componentType、methodName和exceptionClass標(biāo)簽。使用這些自定標(biāo)簽和公共標(biāo)簽,指標(biāo)將按如下方式產(chǎn)出:component_invocation_timer_count{env="local", instanceId="1", appName="samplemicrosvc", componentClass="SampleService", componentType="service", methodName="getUserInformation"} 26.0
查看以下示例注釋:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public?@interface?MonitoredService?{
}
下面的示例代碼展示了一個(gè)簡單的可復(fù)用的切面,用于檢測服務(wù)類
@Configuration
@EnableAspectJAutoProxy
@Aspect
public?class?MonitoringAOPConfig?{
????@Autowired
????MeterRegistry?registry;
????@Pointcut("@target(com.ibm.dip.microsvcengineering.framework.monitoring.MonitoredService)?&&?within(com.ibm.dip..*)")
????public?void?servicePointcut()?{
????}
????@Around("servicePointcut()")
????public?Object?serviceResponseTimeAdvice(ProceedingJoinPoint?pjp)?throws?Throwable?{
????????return?monitorResponseTime(pjp,?TAG_VALUE_SERVICE_TYPE);
????}
????@AfterThrowing(pointcut?=?"servicePointcut()",?throwing?=?"ex")
????public?void?serviceExceptionMonitoringAdvice(JoinPoint?joinPoint,?Exception?ex)
????{
????????monitorException(joinPoint,?ex,?TAG_VALUE_SERVICE_TYPE);
????}
????private?Object?monitorResponseTime(ProceedingJoinPoint?pjp,?String?type)?throws?Throwable?{
????????long?start?=?System.currentTimeMillis();
????????Object?obj?=?pjp.proceed();
????????pjp.getStaticPart();
????????long?end?=?System.currentTimeMillis();
????????String?serviceClass?=?getClassName(pjp.getThis().getClass().getName());
????????String?methodName?=?pjp.getSignature().getName();
????????Timer?timer?=?registry.timer(METER_COMPONENT_TIMER,
????????????????TAG_COMPONENTCLASS,?serviceClass,?TAG_METHODNAME,?methodName,?TAG_OUTCOME,?SUCCESS,?TAG_TYPE,?type);
????????timer.record((end?-?start),?TimeUnit.MILLISECONDS);
????????Counter?successCounter?=?registry.counter(METER_COMPONENT_COUNTER,
????????????????TAG_COMPONENTCLASS,?serviceClass,?TAG_METHODNAME,?methodName,?TAG_OUTCOME,?SUCCESS,?TAG_TYPE,?type);
????????successCounter.increment();
????????return?obj;
????}
????private?void?monitorException(JoinPoint?joinPoint,?Exception?ex,?String?type)
????{
????????String?serviceClass?=?getClassName(joinPoint.getThis().getClass().getName());
????????String?methodName?=?joinPoint.getSignature().getName();
????????Counter?failureCounter?=?registry.counter(METER_COMPONENT_EXCEPTION_COUNTER,?TAG_EXCEPTIONCLASS,
????????????????ex.getClass().getName(),?TAG_COMPONENTCLASS,?serviceClass,?TAG_METHODNAME,?methodName,?TAG_OUTCOME,?ERROR,
????????????????TAG_TYPE,?type);
????????failureCounter.increment();
????}
}
這會將微服務(wù)中的所有檢測邏輯抽象為一組可復(fù)用的切面和注解。微服務(wù)開發(fā)人員只需在類上添加相應(yīng)的注解即可。
該注解的使用實(shí)例如下,通過在 SampleService 類上標(biāo)注該注解,這個(gè)類中的所有方法都會被自動作為 serviceResponseTimeAdvice 和 serviceExceptionMonitoringAdvice 的備選者。
@Service
@MonitoredService
public?class?SampleService?{
???...
}
檢測出站 HTTP/REST 調(diào)用
出站 HTTP/REST 調(diào)用的檢測由 spring-actuator 執(zhí)行。但是,要使其正常工作,RestTemplate 應(yīng)該從一個(gè)名為RestTemplateBuilder 的 bean 中獲得。此外,如果提供了自定義類型的 RestTemplateExchangeTagsProvider bean,則可以將自定義標(biāo)簽添加到指標(biāo)中。
以下配置類說明了這一點(diǎn):
@Bean
public?RestTemplate?restTemplate(RestTemplateBuilder?templateBuilder)
{
????templateBuilder?=?templateBuilder.messageConverters(new?MappingJackson2HttpMessageConverter())
????????????.requestFactory(this::getClientHttpRequestFactory);
????return?templateBuilder.build();
}
@Bean
public?RestTemplateExchangeTagsProvider?restTemplateExchangeTagsProvider()
{
????return?new?RestTemplateExchangeTagsProvider()?{
????????@Override
????????public?Iterable?getTags(String?urlTemplate,?HttpRequest?request,?ClientHttpResponse?response)? {
????????????Tag?uriTag?=?(StringUtils.hasText(urlTemplate)???RestTemplateExchangeTags.uri(urlTemplate)
????????????????????:?RestTemplateExchangeTags.uri(request));
????????????return?Arrays.asList(RestTemplateExchangeTags.method(request),?uriTag,
????????????????????RestTemplateExchangeTags.status(response),?RestTemplateExchangeTags.clientName(request),
????????????????????Tag.of("componentClass",?"httpClient"),
????????????????????Tag.of("componentType",?"integration"),
????????????????????Tag.of("methodName",?uriTag.getValue()));
????????}
????};
}
檢測 Kafka 消費(fèi)者
Kafka Consumers 默認(rèn)由 Actuator 檢測。Actuator 和 Micrometer 收集了 30 多個(gè)與 Kafka Consumers 相關(guān)的指標(biāo)。通用標(biāo)簽也適用于 Kafka 消費(fèi)者。一些顯著的指標(biāo)包括 kafka_consumer_records_consumed_total_records_total、kafka_consumer_bytes_consumed_total_bytes_total 和 kafka_consumer_records_lag_avg_records。然后,可以按 Kafka-Topics、Kafka-partitions 等維度對它們進(jìn)行分組。
檢測 Kafka 生產(chǎn)者
默認(rèn)情況下,Actuator 不檢測 Kafka 生產(chǎn)者。Kafka Producer 有自己的 Metrics 實(shí)現(xiàn)。要使用 Micrometer 注冊這些指標(biāo),需要為每一個(gè) KafkaProducer,?> 定義一個(gè) MeterBinder 類型的 bean。這個(gè) MeterBinder通過 Micrometer Registry 完成量規(guī)(Gauges)的創(chuàng)建與注冊。使用這種方法,可以收集 50 多個(gè) Kafka Producer 指標(biāo)。通用標(biāo)簽和附加標(biāo)簽(在構(gòu)建儀表期間)將為這些指標(biāo)提供多個(gè)維度。
以下代碼顯示了一個(gè)常見的 MeterBinder 實(shí)現(xiàn)是什么樣的:
public?class?KafkaProducerMonitor?implements?MeterBinder?{
????//Filter?out?metrics?that?don't?produce?a?double
????private?Set?filterOutMetrics;
????//Need?to?store?the?reference?of?the?metric?-?else?it?might?get?garbage?collected.?KafkaMetric?is?a?custom?implementation?that?holds?reference?to?the?MetricName?and?KafkaProducer
????private?Set?bindedMetrics;
????private?KafkaProducer,?>?kafkaProducer;
????private?Iterable?tags;
????public?KafkaProducerMonitor(KafkaProducer?kafkaProducer,?MeterRegistry?registry,?Iterable?tags)
????{
???????...
????}
????@Override
????public?void?bindTo(MeterRegistry?registry)?{
????????Map?metrics?=?kafkaProducer.metrics();
????????if?(MapUtils.isNotEmpty(metrics))
????????{
????????????metrics.keySet().stream().filter(metricName?->?!filterOutMetrics.contains(metricName.name()))
????????????????????.forEach(metricName?->?{
????????????????????????logger.debug("Registering?Kafka?Producer?Metric:?{}",?metricName);
????????????????????????KafkaMetric?metric?=?new?KafkaMetric(metricName,?kafkaProducer);
????????????????????????bindedMetrics.add(metric);
????????????????????????Gauge.builder("kafka-producer-"?+?metricName.name(),?metric,?KafkaMetric::getMetricValue)
????????????????????????????????.tags(tags)
????????????????????????????????.register(registry);
????????????????????});
????????}
????}
}
「注意:」 還有其他第三方組件會生成指標(biāo)但未與 Micrometer 集成。在這種情況下,可以利用上述模式;一個(gè)例子是Apache Ignite。
集成 Camel
如果需要集成 Apache Camel ,則需要在應(yīng)用程序中對 Routes 進(jìn)行集成和處理。在路由級別獲取指標(biāo)也是有意義的。Camel 通過其 camel-micrometer組件:https://camel.apache.org/components/latest/micrometer-component.html為 Micrometer 提供端點(diǎn)。在應(yīng)用程序的 pom 中添加 camel-micrometer 依賴項(xiàng)使 Micrometer 端點(diǎn)能夠啟動或停止計(jì)時(shí)器和遞增計(jì)數(shù)器。這些可用于收集路由級別的指標(biāo)。其他特定于 Camel 的 bean,例如 org.apache.camel.Processor那些 type 的,可以使用前面描述的 AOP 方法檢測。
要啟用 micrometer 服務(wù),請?zhí)砑?camel-micrometer 依賴項(xiàng),如下所示:
<dependency>
????<groupId>org.apache.camelgroupId>
????<artifactId>camel-micrometerartifactId>
dependency>
要發(fā)布路由的指標(biāo),RouteBuilder 應(yīng)向 Micrometer 發(fā)送消息,代碼如下:
@Override
public?void?configure()?throws?Exception?{
?????from(inputEndpoints).
???????routeId(routeId).
???????to("micrometer:timer:route_timer"?+?"?"?+?"action=start"?+?"&"?+?"routeName=" ).
???????to("micrometer:counter:route_counter"?+?"?"?+?"routeName=" )
???????...?//other?route?components
???????...?//and?finally
???????to("micrometer:timer:route_timer"?+?"?"?+?"action=stop"?+?"&"?+?"routeName=" );
}
儀器摘要
如你所見,可以使用以下方法收集大量指標(biāo)并將其推送到 Prometheus:
Actuator 提供的開箱即用指標(biāo)。 通過使用 AOP 和 MeterBinder。所有這些自定義檢測代碼都是可復(fù)用的,并且可以封裝為一個(gè)庫,供所有微服務(wù)實(shí)現(xiàn)使用。
這兩種方法都提供了一種一致且侵入性最小的方式來收集跨多個(gè)微服務(wù)及其多個(gè)實(shí)例的指標(biāo)。
Prometheus 與其他第三方系統(tǒng)的集成
Prometheus 有一個(gè)健康的發(fā)展生態(tài)系統(tǒng)。有多個(gè)庫和服務(wù)器可用于將第三方系統(tǒng)的指標(biāo)導(dǎo)出到 Prometheus,這些庫和服務(wù)器在 Prometheus Exporters:https://prometheus.io/docs/instrumenting/exporters/進(jìn)行了編排。例如,mongodb_exporter 可用于將 MongoDB 指標(biāo)導(dǎo)出到 Prometheus。
Apache Kafka 使其指標(biāo)可用于 JMX,它們可以導(dǎo)出到 Prometheus,下個(gè)章節(jié)將會介紹。
將 Kafka 與 Prometheus 集成
如果您使用 Kafka 作為消息/事件代理,那么 Kafka 指標(biāo)與 Prometheus 的集成并不是開箱即用的,需要使用到 jmx_exporter:https://github.com/prometheus/jmx_exporter這個(gè)組件。同時(shí)還需要在 Kafka 的 Brokers 上進(jìn)行配置,然后 Brokers 將通過 HTTP 提供指標(biāo)。jmx_exporter 需要配置文件 (.yml)。示例代碼庫的 examples 文件夾中提供了示例配置 jmx_exporter。
在本教程中,我們構(gòu)建自定義 Kafka 映像僅用于演示目的。jmx_exporter 代碼存儲庫的 README.md 中提供了構(gòu)建自定義 Kafka 映像的說明。
在 Grafana 中構(gòu)建儀表盤
一旦指標(biāo)在 Prometheus Meter Registry 中注冊并且 Prometheus 成功啟動并運(yùn)行,它將開始收集指標(biāo)。這些指標(biāo)現(xiàn)在可用于在 Grafana 中構(gòu)建不同的監(jiān)控儀表盤。不同的端點(diǎn)需要多個(gè)儀表板。建議創(chuàng)建以下這些儀表盤:
「平臺概覽儀表盤」,提供每個(gè)微服務(wù)和平臺其他軟件組件(例如 Kafka)的可用性狀態(tài)。這種類型的儀表板還可以報(bào)告平臺級別的聚合指標(biāo) 請求率(HTTP 請求率、Kafka 消費(fèi)請求率等)和異常數(shù)量.「微服務(wù)下探儀表盤」,提供微服務(wù)實(shí)例的詳細(xì)指標(biāo)。在 Grafana 中聲明 variables很重要,它們對應(yīng)于指標(biāo)中使用的不同標(biāo)簽。例如appName,env,instanceId等。「中間件監(jiān)控儀表盤」,提供中間件組件的詳細(xì)下探視圖。這些特定于中間件(例如,Kafka 儀表盤)。在這里, 變量聲明很重要,以便可以在集群級別和實(shí)例級別上觀察指標(biāo)。
使用維度進(jìn)行下探和聚合
在報(bào)告指標(biāo)時(shí),會將標(biāo)簽添加到指標(biāo)中。這些標(biāo)簽可在 Prometheus 查詢中用于聚合或深入了解指標(biāo)。例如,在平臺級別,人們想查看平臺中的異??倲?shù)。這可以使用以下查詢輕松完成:
sum(component_invocation_exception_counter_total{env="$env"})
結(jié)果為:

現(xiàn)在要在方法和異常類型級別深入研究相同的指標(biāo),Prometheus 查詢將如下所示:
sum by(appName, instanceId, componentClass, methodName, exceptionClass)(component_invocation_exception_counter_total{env="$env", appName="$application", instance="$instance"})
細(xì)節(jié)信息如下:

注意 $ 變量。在儀表盤中該符號可以被定義為變量。Grafana 將根據(jù) Prometheus 中可用的不同指標(biāo)填充它們。儀表盤的用戶可以選擇他們各自的填充值,這可用于動態(tài)更改指標(biāo)可視化,而無需在 Grafana 中創(chuàng)建新的可視化。
作為另一個(gè)示例,以下 prometheus 查詢可用于可視化特定微服務(wù)實(shí)例中服務(wù) bean 的吞吐量。
rate(component_invocation_timer_seconds_count{instance="$instance", appName="$application", componentType="service"}[1m])",
儀表盤示例
以下儀表盤在平臺級別可視化指標(biāo):

該儀表盤提供:
所有 REST 控制器方法的 HTTP 請求率和 Kafka 消費(fèi)者的消費(fèi)率
所有微服務(wù)實(shí)例和 Kafka 集群的可用性狀態(tài)。
請注意,這里的每個(gè)可視化都是特定微服務(wù)實(shí)例的超鏈接,它提供導(dǎo)航到該微服務(wù)實(shí)例下探的詳細(xì)儀表盤。
所有微服務(wù)實(shí)例失敗的 HTTP 請求和服務(wù)錯誤。
所有微服務(wù)實(shí)例的異常細(xì)分。
微服務(wù)下探儀表盤示例
該儀表盤被分成多個(gè)部分,在 Grafana 中稱為“行”。此儀表盤提供微服務(wù)特定實(shí)例的所有指標(biāo)。請注意,它是一個(gè)單一的儀表板,具有環(huán)境、微服務(wù)、instanceId 等的用戶輸入。通過更改這些用戶輸入中的值,可以查看平臺任何微服務(wù)的指標(biāo)。
「注意:」 有多個(gè)屏幕截圖,因?yàn)橛性S多指標(biāo)已被可視化以進(jìn)行演示。
不同的指標(biāo)部分

微服務(wù)實(shí)例級別指標(biāo)

HTTP 控制器指標(biāo)

服務(wù)指標(biāo)

HTTP 客戶端指標(biāo)

Kafka 生產(chǎn)者指標(biāo)

JDBC 連接池指標(biāo)

Kafka 儀表盤示例
Kafka broker 指標(biāo)

Kafka 消息統(tǒng)計(jì)

總結(jié)
通過 spring-boot-actuator、micrometer 和 spring-aop,監(jiān)控 Spring Boot 微服務(wù)變得輕松簡單。利用這些強(qiáng)大的框架,就可以為微服務(wù)建立全面的監(jiān)控能力。
監(jiān)控的一個(gè)重點(diǎn)是跨多個(gè)微服務(wù)及其多個(gè)實(shí)例的指標(biāo)的一致性,即使有數(shù)百個(gè)微服務(wù),這也會使得監(jiān)控和故障排除變得容易和直觀。
監(jiān)測的另一個(gè)重點(diǎn)是不同的視角(viewpoints)。這可以通過使用指標(biāo)的維度和速率聚合特性來實(shí)現(xiàn)。Prometheus 和 Grafana 等工具開箱即用地支持這一點(diǎn)。開發(fā)人員只需要確保產(chǎn)出的指標(biāo)上有正確的標(biāo)簽(這又可以通過通用的或可復(fù)用的切面以及 Spring 配置來輕松實(shí)現(xiàn))。
通過應(yīng)用此指南,可以對所有微服務(wù)進(jìn)行一致且全面的監(jiān)控,而將侵入性的膠水代碼減到最少。
示例代碼
本文翻譯自:https://developer.ibm.com/tutorials/monitor-spring-boot-microservices/,本教程中提供的代碼示例可在原文中找到,或加我微信領(lǐng)取。
