一、Spring Boot Actuator簡介
官方文檔:https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html
Spring Boot Actuator(以下簡稱SBA)主要用於Spring Boot應用的健康檢查,配合K8S可用於服務部署,切換流量,監控報警等場景。
1. 舉個例子:
(1) 賬戶服務,線上運行版本為1.0.0,准備上線1.1.0,要求上線過程不可中斷客戶請求;為此,我們需要在保持1.0.0運行的同時部署1.1.0,在部署完1.1.0並且保證其已經Ready之后,我們讓網關把部分/全部流量切換進來(前者屬於灰度發布,后者是藍綠發布)。如果這個過程是自動化的,我們如何讓程序感知1.1.0版本已經Ready呢?注意,Ready這個狀態未必僅指應用啟動,可能啟動之后還需要加載數據,或者有其他初始化工作,只有這些工作全部完成才算Ready。
Spring Boot Actuator的readiness接口便是為此而設計的。
(2) 用戶服務,它強依賴於賬戶服務,我們希望當賬戶服務無法訪問的情況下,用戶服務可以感知,並且主動拒絕外部請求。針對這種場景,可通過自定義HealthIndicator的方式來實現。
2. 本文的應用對象為Kubernetes環境下的健康檢查。
二、liveness和readiness
Kubernetes有兩個Probes(探針, 請求者),分別是liveness和readiness。相應的SBA也提供了兩個接口,分別是liveness和readiness。
1. liveness,表示Spring Boot應用的存活狀態。SBA認為,liveness的狀態不應依賴外部系統的狀態,外部系統包括數據庫、中間件、外部接口等;它僅僅表示應用本身是否活着。取值如下:
2. readiness,表示Spring Boot應用是否做好准備接受外部請求。SBA認為,readiness一定要考慮應用自身依賴的外部系統狀態,例子2很好的說明了這一點。取值如下:
3. Spring Boot的生命周期
(1) 啟動階段
階段 | Liveness狀態 | Readiness狀態 | 備注 |
Starting | BROKEN | REFUSING_TRAFFIC | K8S檢查"liveness"探針狀態,如果長期沒有影響,則重啟服務。 |
Started | CORRECT | REFUSING_TRAFFIC | 刷新Spring Boot應用上下文,執行其他啟動任務,此時仍處於拒絕接受流量的狀態。 |
Ready | CORRECT | ACCEPTING_TRAFFIC | 啟動完成,應用開始接受請求。 |
(2) 關閉階段
階段 | Liveness狀態 | Readiness狀態 | 備注 |
Running | live | ready | Shutdown開始執行。 |
Graceful shutdown | live | unready | 所謂優雅的關閉,是指讓已經進入應用的請求處理完畢,且在此階段拒絕接受新的請求進入。 |
Shutdown complete | broken | unready | 完成關閉。 |
三、監控什么?
我們需要監控的,一定是影響應用運行的因素。根據空間的划分,我們可以把監控目標分為本地依賴和遠程依賴。
1. 本地依賴主要包括:
(1) 內存空間
(2) 硬盤空間
(3) 環境變量
(4) 配置文件
2. 遠程依賴又可分為:
(1) 遠程軟件依賴,比如數據庫、中間件、FTP或搜索引擎等;
(2) 遠程接口依賴。
四、怎樣監控?
1. 本地依賴
(1) 內存空間,假設應用實例出現內存溢出,我們應該設置應用的liveness狀態為down,使調度器感知,發出報警,切換流量到其他實例,並重啟該實例,這樣可以避免線上出現宕機;
(2) 磁盤空間,如果應用需要保存大量文件到本地,就有必要監控磁盤空間占有量,如果空置率低到一定水平,應該設置應用的readiness狀態為down,使調度器將請求切換到其他實例;
2. 遠程依賴
(1) 軟件依賴,至少需要從連通性上進行監控,如果發現無法連同,則需要設置應用的readiness狀態為down,使調度器將請求切換到其他實例,或拒絕請求;
(2) 接口依賴,主要圍繞着接口的連通性和可用性進行監控,如果接口服務可以提供readiness接口,可直接訪問該接口來實現。
五、Spring Boot Actuator重要概念
1. Endpoints
可以把Endpoints理解為一個功能模塊,功能模塊可以監控Spring Boot應用,甚至可以與Spring Boot進行交互(比如讀取信息,關閉應用等操作)。Spring Boot內置了很多Endpoints,對我們來講最重要的Endpoints是health,即健康檢查模塊。
除health外,常用的Endpoints還包括:
(1) env,用於輸出環境變量;
(2) beans,用於顯示應用中所有的bean對象;
(3) info,可以配置一些自定義信息。
a. 默認情況下,除shutdown以外,所有的Endpoints均是enable狀態。如果希望disable所有Endpoints,可在application.properties中配置:
management.endpoints.enabled-by-default=false
b. 如果希望enable指定Endpoints,可配置:
management.endpoint.<name>.enabled=true
例如:
management.endpoint.info.enabled=true
c. 默認情況下,只有health和info兩個Endpoints暴露在web環境下,可通過url訪問,如果想暴露其他Endpoints,可配置:
management.endpoints.web.exposure.include=health,info,env
全部暴露可配置成*
management.endpoints.web.exposure.include=*
2. HealthIndicator(健康檢查器)
從概念上講,HealthIndicator從屬於health這個Endpoints。
從代碼上講,它是一個接口,繼承該接口並重寫health方法便可自定義一個健康檢查器。
根據依賴目標的不同,檢查器也不相同,圍繞着常見的依賴,Spring Boot內置了許多Indicator:
上面這些已經默認啟動,下面這倆默認禁用。
首先,讓我們看看這些自帶HealthIndicator的繼承關系:
以MongoHealthIndicator為例,讓我們透過源碼,看看這些HealthIndicator如何進行健康檢查:
事實上,MongoHealthIndicator執行了一段Mongo命令"{ buildInfo: 1 }",以此來判斷Mongo的連通性。
3. Health信息
(1) Spring Boot啟動后,訪問
http://<Spring Boot Domain>/actuator
即可查看該實例所有已經暴露到Web的Endpoints。
(2) 查看健康信息
/actuator/health
如果希望得到詳細的健康信息,則添加配置:
management.endpoint.health.show-details=always
(3) Health狀態
如果一切OK,則是UP狀態;如果有依賴掛掉,則是DOWN狀態。
(4) Health數據是如何產生的?
在(2)中我們看到,訪問/actuator/health得到的是系統整體的健康信息。默認情況下,SBA自動enable了所有HealthIndicator。
如果想關掉所有默認打開的HealthIndicator,配置:
management.health.defaults.enabled=false
如果想enable指定的HealthIndicator,配置
management.health.<key>.enabled=true
key的取值參考五.2中的表格。
4. 自定義HealthIndicator
(1) 官網例子
import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.stereotype.Component; @Component public class MyHealthIndicator implements HealthIndicator { @Override public Health health() { int errorCode = check(); //執行健康檢查 if (errorCode != 0) { return Health.down().withDetail("Error Code", errorCode).build(); } return Health.up().build(); } }
(2) 再來個栗子
假設我們的項目依賴https://api.github.com/
@Component public class GitHubAPIHealthIndicator implements HealthIndicator { private final RestTemplate restTemplate; @Override public Health health() { try { ParameterizedTypeReference<Map<String, String>> reference = new ParameterizedTypeReference<Map<String, String>>() {}; ResponseEntity<Map<String, String>> result = restTemplate.exchange("https://api.github.com/", HttpMethod.GET, null, reference);
if (result.getStatusCode().is2xxSuccessful() && result.getBody() != null) { return Health.up().withDetails(result.getBody()).build(); } else { return Health.down().withDetail("status", result.getStatusCode()).build(); } } catch (RestClientException ex) { return Health.down().withException(ex).build(); } } }
訪問/actuator/health
5. Health Groups
(1) 如果你想將若干指定的HealthIndicator捆綁起來構成一組健康檢查,那么可配置:
management.endpoint.health.group.custom.include=db
訪問
/actuator/health/custom
即可獲得custom這個組的健康狀態。
(2) SBA創建了兩個默認的組,liveness和readiness。
默認情況下,只有當Spring Boot應用部署到K8S內,才可以訪問liveness和readiness接口,如果你希望在本地訪問這兩個接口,需要配置:
management.endpoint.health.probes.enabled=true
接口訪問方式為:
/actuator/health/liveness/actuator/health/readiness
(3) 既然liveness和readiness也是Health Groups,那么我們就可以自定義它們包含的HealthIndicator對象:
management.endpoint.health.group.liveness.include=livenessState,customCheck
management.endpoint.health.group.readiness.include=readinessState,db
此時liveness會執行LivenessStateHealthIndicator和CustomCheckHealthIndicator兩個檢查器,readiness會執行ReadinessStateHealthIndicator和數據庫檢查。
三、基本配置和應用
1. pom引用
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
作為spring-boot-starter-parent自帶的組件,我們無需指定它的版本號。
2. 在application.properties中添加配置
management.endpoints.web.exposure.include=info, health, env management.endpoint.health.show-details=always management.endpoint.health.probes.enabled=true