Spring Boot Actuator詳解與深刻應用(二):Actuator 2.x

《Spring Boot Actuator詳解與深刻應用》預計包括三篇,第一篇重點講Spring Boot Actuator 1.x的應用與定製端點;第二篇將會對比Spring Boot Actuator 2.x 與1.x的區別,以及應用和定製2.x的端點;第三篇將會介紹Actuator metric指標與Prometheus和Grafana的使用結合。這部份內容很經常使用,且較爲入門,歡迎你們的關注。html

前文回顧

本文系《Spring Boot Actuator詳解與深刻應用》中的第二篇。在上一篇文章:Spring Boot Actuator詳解與深刻應用(一):Actuator 1.x主要講了Spring Boot Actuator 1.x的應用與定製端點。Spring Boot2.0的正式版已經發布有一段時間了,目前已經到了2.1.0.RELEASE。關於Spring Boot2.x的特性,在此不詳細敘述了,可是其流行的趨勢是顯而易見的。java

本文將會對比Spring Boot Actuator 2.x 與1.x的區別,以及應用和定製2.x的端點。重點介紹最新的2.x版本的Actuator。react

Actuator 2.x

Actuator 2.x繼續保持其基本功能,但簡化其模型,擴展其功能幷包含合適的默認值。首先,這個版本變得與特定框架解耦;此外,它經過將其與應用程序合併來簡化其安全模型;最後,在各類變化中,有些變化是巨大的,這包括HTTP請求/響應以及提供的Java API。此外,最新版本支持CRUD模型,而不是舊的RW(讀/寫)模型。git

在Actuator 1.x中,它與Spring MVC綁定,所以與Servlet API相關聯。而在2.x中,Actuator定義了它的模型可插拔且可擴展,而不依賴於MVC。所以,經過這個新模型,咱們能夠像MVC同樣使用WebFlux做爲底層Web技術。此外,之後的框架能夠經過實現特定的適配器來增長到這個模型中。在沒有任何額外的代碼的狀況下,JMX仍然支持暴露端點。github

快速開始

引入以下的依賴:web

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
複製代碼

和使用的Spring Boot Actuator 1.x並無太大的區別。redis

Actuator 2.x的變化

不一樣於以前的Actuator 1.x,Actuator 2.x 的大多數端點默認被禁掉。 Actuator 2.x 中的默認端點增長了/actuator前綴。spring

默認暴露的兩個端點爲/actuator/health 和 /actuator/info。咱們能夠經過設置以下的屬性:數據庫

management.endpoints.web.exposure.include=*
複製代碼

可使得全部的端點暴露出來。此外,咱們也能夠列出須要暴露的端點或者排除某些端點。如:json

management.endpoints.web.exposure.exclude=env,beans
複製代碼

默認端點

下面咱們看一下可用的端點,他們大部分在1.x中已經存在。儘管如此,有些端點新增,有些被刪除,有些被重構。

  • /auditevents:同Actuator 1.x,還能夠經過關鍵字進行過濾
  • /beans:同Actuator 1.x,不能夠過濾
  • /conditions:返回服務中的自動配置項
  • /configprops:容許咱們獲取@ConfigurationProperties的bean對象
  • /env:返回當前的環境變量,咱們也能夠檢索某個值
  • /flyway:提供Flyway數據庫遷移的詳細狀況
  • /health:同Actuator 1.x
  • /heapdump:返回應用服務使用地jvm堆dump信息
  • /info:同Actuator 1.x
  • /liquibase:相似於 /flyway,可是組件工具爲Liquibase
  • /logfile:返回應用的普通日誌文件
  • /loggers:容許咱們查詢和修改應用的日誌等級
  • /metrics:同Actuator 1.x
  • /prometheus:返回與/metrics相似,與Prometheus server一塊兒使用
  • /scheduledtasks:返回應用的週期性任務
  • /sessions:同Actuator 1.x
  • /shutdown:同Actuator 1.x
  • /threaddump:dump所依賴的jvm線程信息

Actuator的端點安全

Actuator端點是敏感的,必須防止未經受權的訪問。 若是應用程序中存在Spring Security,則默認狀況下使用基於表單的HTTP基自己份驗證來保護端點。使用Spring Security保護Actuator的端點訪問。

引入依賴

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-security</artifactId>
</dependency>
複製代碼

安全配置

爲了應用Actuator的安全規則,咱們增長以下的配置:

@Bean
public SecurityWebFilterChain securityWebFilterChain( ServerHttpSecurity http) {
    return http.authorizeExchange()
      .pathMatchers("/actuator/**").permitAll()
      .anyExchange().authenticated()
      .and().build();
}
複製代碼

如上的配置使得全部訪問/actuator開頭的URL都必須是登陸的狀態。咱們還可使用更加細化的配置:

@Configuration
public class ActuatorSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                    .requestMatchers(EndpointRequest.to(ShutdownEndpoint.class))
                        .hasRole("ACTUATOR_ADMIN")
                    .requestMatchers(EndpointRequest.toAnyEndpoint())
                        .permitAll()
                    .requestMatchers(PathRequest.toStaticResources().atCommonLocations())
                        .permitAll()
                    .antMatchers("/")
                        .permitAll()
                    .antMatchers("/**")
                        .authenticated()
                .and()
                .httpBasic();
    }
}
複製代碼

如上的配置主要實現了:

  • 限定訪問Shutdown端點的角色只能是ACTUATOR_ADMIN
  • 容許訪問其餘全部的端點
  • 容許訪問靜態資源
  • 容許訪問根目錄'/'
  • 全部的請求都要通過認證
  • 容許http靜態認證(可使用任何形式的認證)

測試

爲了可以使用HTTP基自己份驗證測試上述配置,能夠添加默認的spring安全性用戶:

spring:
  security:
    user:
      name: actuator
      password: actuator
      roles: ACTUATOR_ADMIN
複製代碼

/health端點

與之前的版本同樣,咱們能夠輕鬆添加自定義指標。建立自定義健康端點的抽象保持不變。與Spring Boot 1.x不一樣,endpoints.<id> .sensitive屬性已被刪除。/health端點公開的運行情況信息取決於:

management.endpoint.health.show-details
複製代碼

該屬性可使用如下值之一進行配置:

  • never:不展現詳細信息,up或者down的狀態,默認配置
  • when-authorized:詳細信息將會展現給經過認證的用戶。受權的角色能夠經過management.endpoint.health.roles配置。
  • always:暴露詳細信息

/health端點有不少自動配置的健康指示器:如redis、rabbitmq等組件。

當如上的組件有一個狀態異常,應用服務的總體狀態即爲down。咱們也能夠經過配置禁用某個組件的健康監測

management.health.mongo.enabled: false
複製代碼

或者禁用全部自動配置的健康指示器:

management.health.defaults.enabled: false
複製代碼

除此以外,還添加了新的接口ReactiveHealthIndicator以實現響應式運行情況檢查。

引入依賴

<dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-core</artifactId>
        </dependency>
複製代碼

自定義reactive健康檢查

@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());
    }
}
複製代碼

健康指標的一個便利功能是咱們能夠將它們聚合爲層次結構的一部分。 所以,按照上面的示例,咱們能夠將全部下游服務分組到下游服務類別下。只要每一個嵌套服務均可以訪問,這次訪問就是健康的。

/metrics端點

在Spring Boot 2.0中,有一個bean類型爲MeterRegistry將會被自動配置,而且MeterRegistry已經包含在Actuator的依賴中。以下爲咱們得到的/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",
	"description": "Time spent in GC pause",
	"baseUnit": "seconds",
	"measurements": [{
		"statistic": "COUNT",
		"value": 2.0
	}, {
		"statistic": "TOTAL_TIME",
		"value": 0.07300000000000001
	}, {
		"statistic": "MAX",
		"value": 0.0
	}],
	"availableTags": [{
		"tag": "cause",
		"values": ["Metadata GC Threshold"]
	}, {
		"tag": "action",
		"values": ["end of minor GC", "end of major GC"]
	}]
}
複製代碼

咱們能夠看到,如今的指標要詳細得多。不只包括不一樣的值,還包括一些相關的元數據。

/info端點

/info端點沒有什麼變化,咱們能夠經過maven或者gradle引入依賴,增長git的詳細信息。

<dependency>
    <groupId>pl.project13.maven</groupId>
    <artifactId>git-commit-id-plugin</artifactId>
</dependency>
複製代碼

一樣的,咱們可使用maven和gradle的插件,獲取到構建的name,group和version(須要類路徑下存在META-INF/build-info.properties文件)。

<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已經更新了自定義端點的方法,下面咱們定義一個能夠查詢、開啓或者關閉features標誌位的端點。

@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;

		//...
    }

}
複製代碼

定義的端點路徑由@Endpoint中的id屬性決定,在如上的例子中,請求的端點地址爲/actuator/features。並用以下的方法註解來定義操做:

  • @ReadOperation:HTTP GET
  • @WriteOperation:HTTP POST
  • @DeleteOperation:HTTP DELETE

啓動應用,能夠看到控制檯多了以下的日誌輸出:

[...].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如何暴露咱們的端點,至於切換到Spring MVC,咱們只須要引入依賴便可,並不須要更改任何代碼。

以前方法上的元數據信息(sensitive, enabled)都不在使用了,開啓或禁用端點,使用@Endpoint(id = 「features」, enableByDefault = false)。相比於舊的讀寫模型,咱們可使用@DeleteOperation定義DELETE操做。

擴展端點

咱們還能夠經過註解@EndpointExtension擴展事先定義好的端點,更精確的註解爲:@EndpointWebExtension@EndpointJmxExtension

@Component
@EndpointWebExtension(endpoint = InfoEndpoint.class)
public class InfoWebEndpointExtension {
 
    private InfoEndpoint delegate;
 
    @Autowired
    public InfoWebEndpointExtension(InfoEndpoint delegate) {
        this.delegate = delegate;
    }
 
    @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;
    }
}
複製代碼

總結

本文主要講了Actuator 2.x相關特性和使用,對比了與Actuator 1.x 在使用上的區別。Actuator 2.x不依賴於某個框架組件(如Spring MVC),作到了易於插拔和擴展。當咱們想要切換到Webflux時,經過Actuator 2.x中的適配器,不須要更改任何代碼便可實現。 本文源碼:github.com/keets2012/S…

訂閱最新文章,歡迎關注個人公衆號

微信公衆號

參考

  1. Actuator docs
  2. Spring Boot Actuator
相關文章
相關標籤/搜索