簡介:SpringBoot 微服務的開發、發布與部署只占其生命周期的一小部分,應用和系統運維才是重中之重。而運維過程中,監控工作更是占據重要位置。那么,為了對系統的狀態進行持續地觀測,面向Spring Boot應用我們該如何快速實現Prometheus監控接入。本文為大家詳細講解完整接入流程與接入事項!
作者:凡星
對於開發者而言,大部分傳統 SSM 結構的 MVC 應用背后的糟糕體驗都是來自於搭建項目時的大量配置,稍有不慎就可能踩坑。為了解決上述問題,Spring Boot 應運而生。正如其名,Spring Boot 的核心價值就是自動配置,只要存在相應 jar 包,Spring 可以自動配置。如果默認配置不能滿足需求,還可以替換掉自動配置類,使用自定義配置,快速構建企業級應用程序。
但構建 Spring Boot 應用只是第一步,隨着應用上線之后,我們又該如何進行監測?
基礎知識及概念
首先,在正式講解前,先向大家講解本次分享所需要的基本知識和概念。一般來說,搭建一套完整易用的監測系統主要包含以下幾個關鍵部分。
收集監測數據
目前,行業常見的收集監測數據方式主要分為推送(Push)和抓取(Pull)兩個模式。以越來越廣泛應用的 Prometheus 監測體系舉例,Prometheus 就是以抓取(Pull)模式運行的典型系統。應用及基礎設施的監測數據以 OpenMetrics 標准接口的形式暴露給 Prometheus,由 Prometheus 進行定期抓取並長期存儲。
這里簡單介紹一下 OpenMetrics。作為雲原生、高度可擴展的指標協議, OpenMetrics 定義了大規模上報雲原生指標的事實標准,並支持文本表示協議和 Protocol Buffers 協議,文本表示協議在其中更為常見,也是在 Prometheus 進行數據抓取時默認采用的協議。下圖是一個基於 OpenMetrics 格式的指標表示格式樣例。
目前,對於雲原生體系下的絕大多數基礎組件,大多能夠支持以上面提到的 OpenMetrics 的文本協議格式暴露指標,對於尚未能夠支持自身暴露指標的組件, Prometheus 社區也存在極其豐富的 Prometheus Exporter 供開發及運維人員使用。這些組件(或 Exporter)通過響應來自 Prometheus 的定期抓取請求來及時地將自身的運行狀況記錄到 Prometheus 以便后續的處理及分析。對於應用開發者,還可以通過 Prometheus 多語言 SDK,進行代碼埋點,將自身的業務指標也接入到上述的 Prometheus 生態當中。
數據可視化及分析
在獲取應用或基礎設施運行狀態、資源使用情況,以及服務運行狀態等直觀信息后,通過查詢和分析多類型、多維度信息能夠方便的對節點進行跟蹤和比較。同時,通過標准易用的可視化大盤去獲知當前系統的運行狀態。比較常見的解決方案就是 Grafana,作為開源社區中目前熱度很高的數據可視化解決方案,Grafana 提供了豐富的圖表形式與模板。在阿里雲 ARMS Prometheus 監控服務中,也基於 Grafana 向用戶提供了全托管版的監測數據查詢、分析及可視化。
及時的告警和應急管理
當業務即將出現故障時,監測系統需要迅速反應並通知管理員,從而能夠對問題進行快速的處理或者提前預防問題的發生,避免出現對業務的影響。當問題發生后,管理員需要對問題進行認領和處理。通過對不同監測指標以及歷史數據的分析,能夠找到並解決根源問題。
接入流程概覽
接下來,我們講講面向部署在 Kubernetes 集群上的 Spring Boot 微服務應用如何進行 Prometheus 接入。針對 Spring Boot 應用,社區提供了開箱即用的 Spring Boot Actuator 框架,方便 Java 開發者進行代碼埋點和監測數據收集、輸出。從 Spring Boot 2.0 開始,Actuator 將底層改為 Micrometer,提供了更強、更靈活的監測能力。Micrometer 是一個監測門面,可以類比成監測界的 Slf4j 。借助 Micrometer,應用能夠對接各種監測系統,例如:AppOptics,Datadog,Elastic,InfluxDB 等,當然,也包括我們今天所介紹的 Prometheus。
Micrometer 在將 Prometheus 指標對接到 Java 應用的指標時,支持應用開發者用三個類型的語義來映射:
- MicroMeter 中的 Counter 對應於 Prometheus 中的 Counter,用來描述一個單調遞增的變量,如某個接口的訪問次數,緩存命中/訪問總次數等。Timer 在邏輯上蘊含了 Counter,即如果使用 Timer 采集每個接口的響應時間,必然也會采集訪問次數。故無需為某個接口同時指定 Timer 與 Counter 兩個指標
- MicroMeter 中的 Gauge 對應於 Prometheus 中的 Gauge,用來描述在一個范圍內持續波動的變量,如 CPU 使用率,線程池任務隊列數等。
- MicroMeter 中的 Timer 對應於 Prometheus 中的 Histogram,用來描述與時間相關的數據,如某個接口 RT 時間分布等等。
- Micrometer 中的 DistributionSummary 對應 Prometheus 中的 Summary ,與 Histogram 類似,Summary 也是用於統計數據分布的,但由於數據的分布情況是在客戶端計算完成后再傳入 Prometheus 進行存儲,因此 Summary 的結果無法在多個機器之間進行數據聚合,無法統計全局視圖的數據分布,使用起來有一定局限性。
當我們需要把部署在 Kubernetes 集群中的 Spring Boot 應用接入到 Prometheus 時,需要按照代碼埋點->部署應用->服務發現這個流程來進行。
其次,我們將埋點后的應用部署在 Kubernetes 中,並向 Prometheus 注冊向應用拉取監測數據的端點(也就是 Prometheus 服務發現)。阿里雲 Prometheus 服務提供了使用 ServiceMonitor CRD 進行服務發現的方法。
最后在目標應用的監測采集端點被 Prometheus 成功發現后,我們就可以開始在 Grafana 上面配置數據源及相應的大盤了。當然,我們同時也需要根據某些關鍵指標進行對應的告警配置。這些需求在阿里雲 Prometheus 監控服務都能很方便地滿足。
接入流程詳解
接下來,我們進入實戰演練環節,這里選取一個基於 Spring Boot & Spring Cloud Alibaba 構建的雲原生微服務應用()作為我們改造的基線。
我們最終目標是:
1、監測系統的入口:Frontend 服務是一個基於 SpringMVC 開發的入口應用,承接外部的客戶流量,我們主要關注的是外部接口的關鍵 RED 指標(調用率 Rate,失敗數 Error,請求耗時 Duration);
2、監測系統的關鍵鏈路:對后端服務 critical path 上的對象進行監測,如線程池的隊列情況、進程內 Guava Cache 緩存的命中情況;
3、對業務強相關的自定義指標(比如某個接口的 UV 等等);
4、對 JVM GC 及內存使用情況進行監測;
5、對上述指標進行統一匯聚展示、以及配置關鍵指標的告警。
第一步,引入 Spring Boot Actuator 依賴,進行初始配置
首先,我們需要引入 Spring Boot Actuator 的相關依賴,在 application.properties 配置中暴露監測數據端口(這里定義為 8091)。成功后,我們即可訪問應用的 8091 端口的/actuator/prometheus 路徑拿到 OpenMetrics 標准的監測數據。
<!-- spring-boot-actuator依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- prometheus依賴 -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
# application.properties添加以下配置用於暴露指標
spring.application.name=frontend
management.server.port=8091
management.endpoints.web.exposure.include=*
management.metrics.tags.application=${spring.application.name}
第二步,代碼埋點及改造
為了獲取某個 Api 接口的 RED 指標,我們需要在對應的接口方法上打下面的 @Timed 注解。我們以演示項目中的 index 頁面接口為例。注意這里,@Timed 注解中的 value 即為暴露到/actuator/prometheus 中的指標名字,histogram=true 表示我們暴露這個接口請求時長的 histogram 直方圖類型指標,便於我們后續計算 P99,P90 等請求時間分布情況。
@Timed(value = "main_page_request_duration", description = "Time taken to return main page", histogram = true)
@ApiOperation(value = "首頁", tags = {"首頁操作頁面"})
@GetMapping("/")
public String index(Model model) {
model.addAttribute("products", productDAO.getProductList());
model.addAttribute("FRONTEND_APP_NAME", Application.APP_NAME);
model.addAttribute("FRONTEND_SERVICE_TAG", Application.SERVICE_TAG);
model.addAttribute("FRONTEND_IP", registration.getHost());
model.addAttribute("PRODUCT_APP_NAME", PRODUCT_APP_NAME);
model.addAttribute("PRODUCT_SERVICE_TAG", PRODUCT_SERVICE_TAG);
model.addAttribute("PRODUCT_IP", PRODUCT_IP);
model.addAttribute("new_version", StringUtils.isBlank(env));
return "index.html";
}
如果我們的應用中使用了進程內緩存庫,比如最為常見的 Guava Cache 庫等等。如果我們想追蹤進程內緩存的運行狀況,我們需要按照 Micrometer 提供的修飾方法,對待監測的關鍵對象進行封裝。
- Guava Cache 改造主要是四步驟,代碼改動比較小,很容易就可以接入:
1、注入 MeterRegistry,這里注入的具體實現是 PrometheusMeterRegistry,由 Spring Boot 自行注入即可
2、使用工具類 api,即圖中展示的 GuavaCacheMetrics.monitor 包裝一下本地緩存
3、開啟緩存數據記錄,即調用一下.recordStats()方法
4、增加一個名稱,用於生成對應的指標。
- 線程池改造主要是三步驟,也並不是很復雜:
1、注入 MeterRegistry,這里注入的具體實現是 PrometheusMeterRegistry;
2、使用工具類 api 包裝一下線程池;
3、增加一個名稱,用於生成對應的指標。
@Service
public class DemoService {
Counter visitCounter;
public DemoService(MeterRegistry registry) {
visitCounter = Counter.builder("visit_counter")
.description("Number of visits to the site")
.register(registry);
}
public String visit() {
visitCounter.increment();
return "Hello World!";
}
}
至此,我們的應用代碼改造工作到這里就全部完成了,下一步工作就是將應用鏡像重新構建並重新部署到已安裝 ARMS Prometheus 的 Kubernetes 集群中。之后,我們 ARMS Prometheus 控制台中配置 ServiceMonitor,進行服務發現。
第三步,看板配置
應用的監測數據已成功收集並存儲到 ARMS Prometheus。接下來,也是最關鍵的一步,就是根據這些數據,配置相應的大盤及告警。這里,我們借助 Grafana 社區中開源大盤模板來構建我們自己的業務監測模板。主要基於以下兩個模板:
- Spring Boot 2.1 Statistics:
- JVM (Micrometer):
借助這些模板以及 ARMS Prometheus 內置的 Grafana 服務,我們可以很方便地將日常開發和運維過程中非常關心的指標組織在一張的 Grafana Dashboard 上。這里給大家拋磚引玉一下,放一張我們內部基於上述模板和自身業務構建的一個真實的大盤。這里面包含了一些總覽,比如組件運行時間,內存使用率等等,也有一些細節指標,如堆內堆外內存,分代 GC 情況等等,還有像接口請求的 RED 等等,這里就不過多贅述了,大家可以充分發揮自己的想象力來創造獨一無二的酷炫大盤~

本文為阿里雲原創內容,未經允許不得轉載。








