聊聊Spring Boot Actuator
- 2020 年 4 月 28 日
- 筆記
- JAVA, spring, springboot
概述
在本文中,我們將介紹Spring Boot Actuator。我們將首先介紹基礎知識,然後詳細討論Spring Boot 1.x和2.x中的可用內容。
我們將在Spring Boot 1.x中學習如何使用,配置和擴展此監視工具。然後,我們將討論如何利用反應式編程模型使用Boot 2.x和WebFlux進行相同的操作。
自2014年4月起,Spring Boot Actuator隨Spring Boot一起發布。
隨著SpringBoot2的發布,執行器進行了重新設計,並添加了新的激動人心的端點。本指南分為三個主要部分:
- 什麼是執行器(Actuator)
- Spring Boot 1.x Actuator
- Spring Boot 2.x Actuator
👋:執行器==Actuator
什麼是執行器(Actuator)
本質上,執行器為我們的應用帶來了生產就緒功能。
通過對他的依賴,監視我們的應用程式、收集度量、了解流量或資料庫的狀態變得輕鬆簡單:
這個庫的主要好處是,我們可以獲得生產級工具,而不必親自實現這些功能。Actuator主要用於公開有關正在運行的應用程式的操作資訊-運行狀況,指標,資訊,轉儲,環境等。它使用HTTP端點或JMX Bean使我們能夠與其交互。一旦在類路徑上使用執行器,便可以立即使用幾個端點。與大多數Spring模組一樣,我們可以通過多種方式輕鬆地對其進行配置或擴展。
Getting Started
要啟用SpringBootActuator,我們只需要將SpringBootActuator依賴項添加到包管理器中。在Maven:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
請注意,無論引導版本如何,這都保持有效,因為版本是在Spring Boot Bill of Materials(BOM)中指定的
Spring Boot 1.x Actuator
在1.x中,執行器遵循R/W(read/write)模型,這意味著我們可以對其進行讀取或寫入。例如。我們可以檢索指標或應用程式的運行狀況。另外,我們可以優雅地終止我們的應用程式或更改日誌記錄配置。
為了讓它工作,執行器需要Spring MVC通過HTTP公開其端點。不支援其他技術。
Endpoints
在1.x中,Actuator帶來了自己的安全模型。它利用了Spring Security構造,但是需要與應用程式的其餘部分獨立配置。
而且,大多數端點都是敏感的-表示它們不是完全公開的,換句話說,大多數資訊將被省略-而少數端點不是敏感的比如/info。
以下是Boot提供的一些最常見的端點:
-
/health –顯示應用程式運行狀況資訊(通過未經身份驗證的連接訪問時為簡單的「狀態」,或通過身份驗證時顯示為完整的消息詳細資訊);默認情況下不敏感
-
/info –顯示任意應用程式資訊;默認不敏感
-
/metrics –顯示當前應用程式的「指標」資訊;默認情況下是敏感的
-
/trace –顯示跟蹤資訊(默認情況下,最後幾個HTTP請求)
我們可以在官方文檔中找到現有端點的完整列表。
配置現有端點
可以使用以下格式使用屬性來自定義每個端點:endpoints.[endpoint name].[property to customize]
提供三個屬性:
- id –將通過HTTP訪問該端點
- enabled–如果為true,則可以訪問,否則不能訪問
- sensitive–如果為true,則需要授權通過HTTP顯示關鍵資訊
例如,添加以下屬性將自定義/beans端點:
endpoints.beans.id=springbeans endpoints.beans.sensitive=false endpoints.beans.enabled=true
⚠️:上述方法現已被棄用。
/health端點
/health端點用於檢查正在運行的應用程式的運行狀況或狀態。監視軟體通常會執行此操作,以警告我們正在運行的實例出現故障或由於其他原因而變得不正常。例如。資料庫的連接問題,磁碟空間不足…
默認情況下,在未授權狀態下訪問只會顯示運行狀況資訊:
{
"status" : "UP"
}
此健康資訊是從在我們的應用程式上下文中配置的,實現了HealthIndicator介面的所有bean收集的。
HealthIndicator返回的某些資訊本質上是敏感的,但是我們可以配置endpoints.health.sensitive = false來公開更多詳細資訊,例如磁碟空間,消息傳遞代理連接,自定義檢查等。
我們還可以實現自己的自定義運行狀況指示器-可以收集特定於應用程式的任何類型的自定義運行狀況數據,並通過/health端點自動將其公開:
@Component
public class HealthCheck implements HealthIndicator {
@Override
public Health health() {
int errorCode = check();//perform some specific health check
if (errorCode != 0) {
return Health.down()
.withDetail("Error Code", errorCode).build();
}
return Health.up().build();
}
public int check() {
//Our logic to check health
return 0;
}
}
輸出結果如下所示:
{
"status" : "DOWN",
"myHealthCheck" : {
"status" : "DOWN",
"Error Code" : 1
},
"diskSpace" : {
"status" : "UP",
"free" : 209047318528,
"threshold" : 10485760
}
}
/info端點
我們還可以自定義/info端點顯示的數據-例如:
info.app.name=Spring Sample Application
info.app.description=This is my first spring boot application
info.app.version=1.0.0
以及示例輸出:
{
"app" : {
"version" : "1.0.0",
"description" : "This is my first spring boot application",
"name" : "Spring Sample Application"
}
}
/metrics端點
metrics端點發布有關OS、JVM以及應用程式級度量的資訊。啟用後,我們將獲得諸如記憶體、堆、處理器、執行緒、載入的類、卸載的類、執行緒池以及一些HTTP度量等資訊。
以下是該端點的輸出結果:
{
"mem" : 193024,
"mem.free" : 87693,
"processors" : 4,
"instance.uptime" : 305027,
"uptime" : 307077,
"systemload.average" : 0.11,
"heap.committed" : 193024,
"heap.init" : 124928,
"heap.used" : 105330,
"heap" : 1764352,
"threads.peak" : 22,
"threads.daemon" : 19,
"threads" : 22,
"classes" : 5819,
"classes.loaded" : 5819,
"classes.unloaded" : 0,
"gc.ps_scavenge.count" : 7,
"gc.ps_scavenge.time" : 54,
"gc.ps_marksweep.count" : 1,
"gc.ps_marksweep.time" : 44,
"httpsessions.max" : -1,
"httpsessions.active" : 0,
"counter.status.200.root" : 1,
"gauge.response.root" : 37.0
}
為了收集自定義指標,我們支援「儀錶」(即數據的單值快照)和「計數器」(即增/減指標)。
讓我們在/metrics端點中實現我們自己的自定義指標。例如,我們將自定義登錄流程以記錄成功和失敗的登錄嘗試:
@Service
public class LoginServiceImpl {
private final CounterService counterService;
public LoginServiceImpl(CounterService counterService) {
this.counterService = counterService;
}
public boolean login(String userName, char[] password) {
boolean success;
if (userName.equals("admin") && "secret".toCharArray().equals(password)) {
counterService.increment("counter.login.success");
success = true;
}
else {
counterService.increment("counter.login.failure");
success = false;
}
return success;
}
}
輸出結果如下所示:
{
...
"counter.login.success" : 105,
"counter.login.failure" : 12,
...
}
請注意,登錄嘗試和其他安全相關事件作為審計事件在執行器中是現成可用的。
創建新端點
除了使用Spring Boot提供的現有端點之外,我們還可以創建一個全新的端點。
首先,我們需要讓新的端點實現endpoint
@Component
public class CustomEndpoint implements Endpoint<List<String>> {
@Override
public String getId() {
return "customEndpoint";
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public boolean isSensitive() {
return true;
}
@Override
public List<String> invoke() {
//Custom logic to build the output
List<String> messages = new ArrayList<String>();
messages.add("This is message 1");
messages.add("This is message 2");
return messages;
}
}
為了訪問此新端點,將使用其ID對其進行映射,即我們可以按/customEndpoint對其進行訪問。 輸出:
[ "This is message 1", "This is message 2" ]
進一步訂製
為了安全起見,我們可能選擇通過非標準埠公開執行器端點-可以輕鬆地使用management.port屬性進行配置。
同樣,正如我們已經提到的,在1.x中。 Actuator基於Spring Security配置其自己的安全模型,但與應用程式的其餘部分無關。
因此,我們可以更改management.address屬性以限制可以從網路訪問端點的位置:
#port used to expose actuator
management.port=8081
#CIDR allowed to hit actuator
management.address=127.0.0.1
#Whether security should be enabled or disabled altogether
management.security.enabled=false
此外,默認情況下,除/info外的所有內置終結點都是敏感的。如果應用程式使用的是Spring Security,我們可以通過在application.properties文件中定義默認的安全屬性(用戶名,密碼和角色)來保護這些端點:
security.user.name=admin
security.user.password=secret
management.security.role=SUPERUSER
Spring Boot 2.x Actuator
在2.x中,Actuator保持其基本意圖,但簡化了其模型,擴展了其功能並結合了更好的默認設置。
首先,該版本與技術無關。此外,它通過將其與應用程式合併來簡化其安全模型。
最後,在各種更改中,請務必記住其中一些正在停用。這包括HTTP請求/響應以及Java API。
此外,與舊的RW(讀/寫)模型相反,最新版本現在支援CRUD模型。
技術支援
在第二個主要版本中,Actuator現在與技術無關,而在1.x中,它與MVC關聯,因此與Servlet API關聯。
在2.x中,Actuator定義了其模型,可插入且可擴展,而無需依賴MVC。
因此,通過這種新模型,我們能夠利用MVC和WebFlux作為基礎Web技術。
此外,可以通過實現正確的適配器來添加即將出現的技術。
最後,仍然支援JMX公開端點,而無需任何其他程式碼。
重要變化
與以前的版本不同,Actuator禁用了大多數端點。
因此,默認情況下僅有的兩個可用的是/health和/info。
如果要啟用所有這些功能,可以設置management.endpoints.web.exposure.include = *或者,我們可以列出應啟用的端點。
現在,Actuator與我們的應用安全規則共享安全配置。因此,極大地簡化了安全模型。
因此,要調整執行器安全性規則,我們可以為/actuator/**添加一個條目:
@Bean
public SecurityWebFilterChain securityWebFilterChain(
ServerHttpSecurity http) {
return http.authorizeExchange()
.pathMatchers("/actuator/**").permitAll()
.anyExchange().authenticated()
.and().build();
}
我們可以在全新的Actuator官方文檔中找到更多詳細資訊。
同樣,默認情況下,所有執行器端點現在都放在/actuator路徑下。
與上一版本相同,我們可以使用新屬性 management.endpoints.web.base-path調整此路徑。
預定義端點
讓我們看一下一些可用的端點,其中大多數已經在1.x中可用。
儘管如此,仍添加了一些端點,刪除了一些端點,並重新構建了一些端點:
- /auditevents –列出與安全審核相關的事件,例如用戶登錄/註銷。另外,我們可以在其他欄位中按主體或類型進行過濾
- /beans –返回BeanFactory中所有可用的bean。與/auditevents不同,它不支援過濾
- /conditions –以前稱為/autoconfig,圍繞自動配置生成條件報告
- /configprops–允許我們獲取所有@ConfigurationProperties bean
- /env –返回當前環境屬性。此外,我們可以檢索單個屬性
- /flyway –提供有關我們的Flyway資料庫遷移的詳細資訊
- /health –總結我們應用程式的健康狀態
- /heapdump –從我們的應用程式使用的JVM構建並返回堆轉儲
- /info –返回常規資訊。它可能是自定義數據,構建資訊或有關最新提交的詳細資訊
- /liquibase –行為類似於/flyway,但對於Liquibase
- /logfile –返回普通的應用程式日誌
- /loggers –使我們能夠查詢和修改應用程式的日誌記錄級別
- /metrics –詳細說明我們應用程式的指標。這可能包括通用指標和自定義指標
- /prometheus –返回與上一個類似的指標,但其格式可以與Prometheus伺服器一起使用
- /scheduledtasks –提供有關我們應用程式中每個計劃任務的詳細資訊
- /sessions –列出我們正在使用Spring Session的HTTP會話
- /shutdown –正常關閉應用程式
- /threaddump –轉儲底層JVM的執行緒資訊
健康指標
就像以前的版本一樣,我們可以輕鬆添加自定義指標。與其他API相反,用於創建自定義健康狀況端點的抽象保持不變。但是,添加了新介面ReactiveHealthIndicator來實現反應式健康檢查。
讓我們看一個簡單的自定義反應式健康檢查:
@Component
public class DownstreamServiceHealthIndicator implements ReactiveHealthIndicator {
@Override
public Mono<Health> health() {
return checkDownstreamServiceHealth().onErrorResume(
ex -> Mono.just(new Health.Builder().down(ex).build())
);
}
private Mono<Health> checkDownstreamServiceHealth() {
//we could use WebClient to check health reactively
return Mono.just(new Health.Builder().up().build());
}
}
健康指標的一個方便功能是我們可以將它們匯總為層次結構的一部分。因此,按照前面的示例,我們可以將所有下游服務歸為「下游服務」類別。只要可以訪問每個嵌套服務,此類別都是健康的。
複合健康檢查通過CompositeHealthIndicator在1.x中進行。另外,在2.x中,我們可以將CompositeReactiveHealthIndicator用作其響應式副本。
與Spring Boot 1.x中不同的是,endpoints.
Spring Boot 2中的指標
在Spring Boot 2.0中,內部指標已被Micrometer支援所取代。因此,我們可以期待重大的變化。如果我們的應用程式使用的是度量服務,例如GaugeService或CounterService,則它們將不再可用。
相反,我們應該直接與Micrometer進行交互。在Spring Boot 2.0中,我們將自動配置一個類型為MeterRegistry的bean。
此外,Micrometer現在是執行器依賴項的一部分。因此,只要執行器依賴項在類路徑中,我們就應該繼續。
此外,我們將從/metrics端點獲得全新的響應:
{
"names": [
"jvm.gc.pause",
"jvm.buffer.memory.used",
"jvm.memory.used",
"jvm.buffer.count",
//...
]
}
正如我們在前面的示例中觀察到的,沒有像1.x那樣的實際指標。
要獲取特定指標的實際值,我們現在可以導航至所需指標,即/actuator/metrics/jvm.gc.pause並獲取詳細的響應:
{
"name": "jvm.gc.pause",
"measurements": [
{
"statistic": "Count",
"value": 3.0
},
{
"statistic": "TotalTime",
"value": 7.9E7
},
{
"statistic": "Max",
"value": 7.9E7
}
],
"availableTags": [
{
"tag": "cause",
"values": [
"Metadata GC Threshold",
"Allocation Failure"
]
},
{
"tag": "action",
"values": [
"end of minor GC",
"end of major GC"
]
}
]
}
如我們所見,指標現在更加全面。不僅包括不同的值,還包括一些相關的元數據。
自定義/info端點
/info端點保持不變。和以前一樣,我們可以使用Maven或Gradle各自的依賴項添加git詳細資訊:
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<version>2.2.5</version>
<executions>
<execution>
<goals>
<goal>revision</goal>
</goals>
</execution>
</executions>
<configuration>
<dotGitDirectory>${project.basedir}/.git</dotGitDirectory>
</configuration>
</plugin>
同樣,我們還可以使用Maven或Gradle插件來包含構建資訊,包括名稱,組和版本:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
創建自定義端點
如前所述,我們可以創建自定義端點。但是,Spring Boot 2重新設計了實現此目標的方法,以支援與技術無關的新範例。
讓我們創建一個Actuator端點來查詢,啟用和禁用應用程式中的功能標誌:
@Component
@Endpoint(id = "features")
public class FeaturesEndpoint {
private Map<String, Feature> features = new ConcurrentHashMap<>();
@ReadOperation
public Map<String, Feature> features() {
return features;
}
@ReadOperation
public Feature feature(@Selector String name) {
return features.get(name);
}
@WriteOperation
public void configureFeature(@Selector String name, Feature feature) {
features.put(name, feature);
}
@DeleteOperation
public void deleteFeature(@Selector String name) {
features.remove(name);
}
public static class Feature {
private Boolean enabled;
//[...] getters and setters
}
}
為了得到端點,我們需要一個bean。在我們的例子中,我們使用@Component來實現這一點。另外,我們需要用@Endpoint裝飾這個bean。
端點的路徑由@Endpoint的id參數確定,在本例中,它將請求路由到/actuator/features
準備就緒後,我們可以使用以下方法開始定義操作:
- @ReadOperation – it’ll map to HTTP GET
- @WriteOperation – it’ll map to HTTP POST
- @DeleteOperation – it’ll map to HTTP DELETE
當我們使用應用程式中的上一個端點運行該應用程式時,Spring Boot將對其進行註冊。
一種快速的驗證方法是檢查日誌:
[...].WebFluxEndpointHandlerMapping: Mapped "{[/actuator/features/{name}], methods=[GET], produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" [...].WebFluxEndpointHandlerMapping : Mapped "{[/actuator/features], methods=[GET], produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" [...].WebFluxEndpointHandlerMapping : Mapped "{[/actuator/features/{name}], methods=[POST], consumes=[application/vnd.spring-boot.actuator.v2+json || application/json]}" [...].WebFluxEndpointHandlerMapping : Mapped "{[/actuator/features/{name}], methods=[DELETE]}"[...]
在前面的日誌中,我們可以看到WebFlux是如何公開我們的新端點的。如果我們切換到MVC,它只需委託該技術,而不必更改任何程式碼。
此外,對於這種新方法,我們需要牢記一些重要的注意事項:
- 與MVC沒有依賴關係
- 以前作為方法存在的所有元數據(敏感、已啟用…)不再存在。但是,我們可以使用@endpoint啟用或禁用端點(id=「features」,enableByDefault=false)
- 與1.x不同,不再需要擴展給定的介面
- 與舊的讀/寫模型相比,現在我們可以使用@DeleteOperation定義DELETE操作
擴展現有的端點
假設我們要確保應用程式的生產實例不是SNAPSHOT版本。我們決定通過更改返回實例資訊的Actuator端點的HTTP狀態程式碼(即/info)來執行此操作。如果我們的應用碰巧是快照。我們將獲得不同的HTTP狀態程式碼。
我們可以使用@EndpointExtension注釋或其更具體的專門化@EndpointWebExtension或@EndpointJmxExtension輕鬆擴展預定義端點的行為:
@Component
@EndpointWebExtension(endpoint = InfoEndpoint.class)
public class InfoWebEndpointExtension {
private InfoEndpoint delegate;
//standard constructor
@ReadOperation
public WebEndpointResponse<Map> info() {
Map<String, Object> info = this.delegate.info();
Integer status = getStatus(info);
return new WebEndpointResponse<>(info, status);
}
private Integer getStatus(Map<String, Object> info) {
//return 5xx if this is a snapshot
return 200;
}
}
啟用所有端點
為了使用HTTP訪問執行器端點,我們需要同時啟用和公開它們。默認情況下,除/shutdown之外的所有端點均處於啟用狀態。默認情況下僅公開/health和/info端點。
我們需要添加以下配置以公開所有端點:
management.endpoints.web.exposure.include=*
要顯式啟用特定端點(例如/shutdown),我們使用:
management.endpoint.shutdown.enabled=true
要公開除一個(例如/loggers)以外的所有啟用的端點,我們使用:
management.endpoints.web.exposure.include=*
management.endpoints.web.exposure.exclude=loggers
總結
在本文中,我們討論了Spring Boot Actuator。我們開始定義執行器的含義及其對我們的作用。 接下來,我們關注當前Spring Boot版本1.x的Actuator。討論如何使用它,並對它進行擴展。 然後,我們在Spring Boot 2中討論了Actuator。我們專註於新功能,並利用WebFlux公開了端點。
此外,我們還討論了在新迭代中可以找到的重要安全更改。我們討論了一些流行的端點以及它們如何發生變化。
最後,我們演示了如何自定義和擴展執行器。
關注筆者公眾號,推送各類原創/優質技術文章 ⬇️