聊聊Spring Boot Actuator

概述

在本文中,我們將介紹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..sensitive標誌已被刪除。要隱藏完整的健康報告,我們可以利用新的management.endpoint.health.show-details。默認情況下,此標誌爲false。

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公開了端點。

此外,我們還討論了在新迭代中可以找到的重要安全更改。我們討論了一些流行的端點以及它們如何發生變化。

最後,我們演示瞭如何自定義和擴展執行器。


關注筆者公衆號,推送各類原創/優質技術文章 ⬇️

WechatIMG6

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章