牛逼的Spring Boot 服務監控!!
- 2020 年 2 月 20 日
- 筆記
閱讀本文需要5分鐘
前言
去年我們項目做了微服務1.0的架構轉型,但是服務監控這塊卻沒有跟上。這不,最近我就被分配了要將我們核心的微服務應用全部監控起來的任務。我們的微服務應用都是SpringBoot 應用,因此就自然而然的想到了藉助Spring Boot 的Actuator 模組。(沒吃過豬肉總聽過豬叫見過豬跑吧?)。
本篇是我在完成這個工單之後,對Spring Boot Actuator模組 學習應用的總結。在本篇文章中,你可以學習到:
1、Spring Boot Actuator 的快速使用入門 2、Spring Boot Actuator 的一些重要的endpoints的介紹 3、如何通過Actuator 模組實時查看當前應用的執行緒 dump資訊 4、如何通過Actuator 模組實時查看當前應用的堆資訊 5、如何通過Actuator 模組實時修改當前應用的日誌列印等級 6、…
之後我還會介紹:
TODO:SpringBoot 微服務應用集成Prometheus + Grafana實現監控告警
一、什麼是 Spring Boot Actuator
Spring Boot Actuator 模組提供了生產級別的功能,比如健康檢查,審計,指標收集,HTTP 跟蹤等,幫助我們監控和管理Spring Boot 應用、Bean載入情況、環境變數、日誌資訊、執行緒資訊,JVM 堆資訊等 。這個模組是一個採集應用內部資訊暴露給外部的模組,上述的功能都可以通過HTTP 和 JMX 訪問。
因為暴露內部資訊的特性,Actuator 也可以和一些外部的應用監控系統整合(Prometheus, Graphite, DataDog, Influx, Wavefront, New Relic等)。這些監控系統提供了出色的儀錶板,圖形,分析和警報,可幫助你通過一個統一友好的介面,監視和管理你的應用程式。
Actuator使用Micrometer與這些外部應用程式監視系統集成。這樣一來,只需很少的配置即可輕鬆集成外部的監控系統。
Micrometer 為 Java 平台上的性能數據收集提供了一個通用的 API,應用程式只需要使用 Micrometer 的通用 API 來收集性能指標即可。Micrometer 會負責完成與不同監控系統的適配工作。這就使得切換監控系統變得很容易。 對比 Slf4j 之於 Java Logger 中的定位。
二、快速開始,創建一個Spring Boot Actuator Demo
我們先創建一個demo應用。
你可以通過Spring Boot CLI 創建:
spring init -d=web,actuator -n=actuator-demo actuator-demo
或者通過Spring Initializr 創建:

對應的maven依賴:
<dependencies> ... <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> ... </dependencies>
對應的Gradle 依賴:
dependencies { compile("org.springframework.boot:spring-boot-starter-actuator") }
三、Endpoints 介紹
Spring Boot 提供了所謂的 endpoints (下文翻譯為端點)給外部來與應用程式進行訪問和交互。
打比方來說, /health
端點 提供了關於應用健康情況的一些基礎資訊。metrics
端點提供了一些有用的應用程式指標(JVM 記憶體使用、系統CPU使用等)。
這些 Actuator 模組本來就有的端點我們稱之為原生端點。根據端點的作用的話,我們大概可以分為三大類:
應用配置類:獲取應用程式中載入的應用配置、環境變數、自動化配置報告等與Spring Boot應用密切相關的配置類資訊。
度量指標類:獲取應用程式運行過程中用於監控的度量指標,比如:記憶體資訊、執行緒池資訊、HTTP請求統計等。
操作控制類:提供了對應用的關閉等操作類功能。
詳細的原生端點介紹,請以官網為準,這裡就不贅述徒增篇幅。
需要注意的就是:
1、每一個端點都可以通過配置來單獨禁用或者啟動
2、不同於Actuator 1.x,Actuator 2.x 的大多數端點默認被禁掉。Actuator 2.x 中的默認端點增加了 /actuator
前綴。默認暴露的兩個端點為 /actuator/health
和 /actuator/info
四、端點暴露配置
我們可以通過以下配置,來配置通過JMX 和 HTTP 暴露的端點。
可以打開所有的監控點
management.endpoints.web.exposure.include=*
也可以選擇打開部分,"*" 代表暴露所有的端點,如果指定多個端點,用","分開
management.endpoints.web.exposure.exclude=beans,trace
Actuator 默認所有的監控點路徑都在 /actuator/*
,當然如果有需要這個路徑也支援訂製。
management.endpoints.web.base-path=/minitor
設置完重啟後,再次訪問地址就會變成 /minitor/*
。
現在我們按照如下配置:
# "*" 代表暴露所有的端點 如果指定多個端點,用","分開 management.endpoints.web.exposure.include=* # 賦值規則同上 management.endpoints.web.exposure.exclude=
啟動DEMO程式,訪問 http://localhost:8080/actuator
,查看暴露出來的端點:

上面這樣顯示是因為chrome 瀏覽器安裝了 JSON-handle 插件,實際上就是返回一大段json
下面,我會著重介紹幾個比較重要的端點。
五、重要端點解析
5.1 /health
端點
/health
端點會聚合你程式的健康指標,來檢查程式的健康情況。端點公開的應用健康資訊取決於:
management.endpoint.health.show-details=always
該屬性可以使用以下值之一進行配置:
不展示詳細資訊,up或者down的狀態,默認配置
按照上述配置,配置成 always
之後,我們啟動項目,訪問 http://localhost:8080/actuator/health
埠,可以看到這樣的資訊:

是不是感覺好像健康資訊有點少?先別急,那是因為我們創建的是一個最基礎的Demo項目,沒有依賴很多的組件。
/health
端點有很多自動配置的健康指示器:如redis、rabbitmq、db等組件。當你的項目有依賴對應組件的時候,這些健康指示器就會被自動裝配,繼而採集對應的資訊。如上面的 diskSpace 節點資訊就是 DiskSpaceHealthIndicator
在起作用。

上述截圖取自官方文檔
這是我另一個項目的 /health
端點資訊。

當如上的組件有一個狀態異常,應用服務的整體狀態即為down。我們也可以通過配置禁用某個組件的健康監測。
management.health.mongo.enabled: false
或者禁用所有自動配置的健康指示器:
management.health.defaults.enabled: false
⭐自定義 Health Indicator
當然你也可以自定義一個Health Indicator,只需要實現 HealthIndicator
介面或者繼承 AbstractHealthIndicator
類。
/** * @author Richard_yyf * @version 1.0 2020/1/16 */ @Component public class CustomHealthIndicator extends AbstractHealthIndicator { @Override protected void doHealthCheck(Health.Builder builder) throws Exception { // 使用 builder 來創建健康狀態資訊 // 如果你throw 了一個 exception,那麼status 就會被置為DOWN,異常資訊會被記錄下來 builder.up() .withDetail("app", "這個項目很健康") .withDetail("error", "Nothing, I'm very good"); } }
最終效果:

5.2 /metrics
端點
/metrics
端點用來返回當前應用的各類重要度量指標,比如:記憶體資訊、執行緒資訊、垃圾回收資訊、tomcat、資料庫連接池等。
{ "names": [ "tomcat.threads.busy", "jvm.threads.states", "jdbc.connections.active", "jvm.gc.memory.promoted", "http.server.requests", "hikaricp.connections.max", "hikaricp.connections.min", "jvm.memory.used", "jvm.gc.max.data.size", "jdbc.connections.max", .... ] }
不同於1.x,Actuator在這個介面看不到具體的指標資訊,只是展示了一個指標列表。為了獲取到某個指標的詳細資訊,我們可以請求具體的指標資訊,像這樣:
http://localhost:8080/actuator/metrics/{MetricName}
比如我訪問 /actuator/metrics/jvm.memory.max
,返回資訊如下:

你也可以用query param的方式查看單獨的一塊區域。比如你可以訪問 /actuator/metrics/jvm.memory.max?tag=id:Metaspace
。結果就是:

5.3 /loggers
端點
/loggers
端點暴露了我們程式內部配置的所有logger的資訊。我們訪問 /actuator/loggers
可以看到,

你也可以通過下述方式訪問單獨一個logger,
http://localhost:8080/actuator/loggers/{name}
比如我現在訪問 root
logger, http://localhost:8080/actuator/loggers/root
{ "configuredLevel": "INFO", "effectiveLevel": "INFO" }
⭐改變運行時的日誌等級
/loggers
端點我最想提的就是這個功能,能夠動態修改你的日誌等級。
比如,我們可以通過下述方式來修改 root
logger的日誌等級。我們只需要發起一個URL 為 http://localhost:8080/actuator/loggers/root
的 POST
請求,POST報文如下:
{ "configuredLevel": "DEBUG" }

仔細想想,這個功能是不是非常有用。如果在生產環境中,你想要你的應用輸出一些Debug資訊以便於你診斷一些異常情況,你你只需要按照上述方式就可以修改,而不需要重啟應用。
如果想重置成默認值,把value 改成
null
5.4 /info
端點
/info
端點可以用來展示你程式的資訊。我理解過來就是一些程式的基礎資訊。並且你可以按照自己的需求在配置文件 application.properties
中個性化配置(默認情況下,該端點只會返回一個空的json內容。):
info.app.name=actuator-test-demo info.app.encoding=UTF-8 info.app.java.source=1.8 info.app.java.target=1.8 # 在 maven 項目中你可以直接用下列方式引用 maven properties的值 # [email protected]@ # [email protected]@ # [email protected]@
啟動項目,訪問 http://localhost:8080/actuator/info
:
{ "app": { "encoding": "UTF-8", "java": { "source": "1.8.0_131", "target": "1.8.0_131" }, "name": "actuator-test-demo" } }
5.5 /beans
端點
/beans
端點會返回Spring 容器中所有bean的別名、類型、是否單例、依賴等資訊。
訪問 http://localhost:8080/actuator/beans
,返回如下:

5.6 /heapdump
端點
訪問:http://localhost:8080/actuator/heapdump
會自動生成一個 Jvm 的堆文件 heapdump。我們可以使用 JDK 自帶的 Jvm 監控工具 VisualVM 打開此文件查看記憶體快照。

5.7 /threaddump
端點
這個端點我個人覺得特別有用,方便我們在日常定位問題的時候查看執行緒的情況。主要展示了執行緒名、執行緒ID、執行緒的狀態、是否等待鎖資源、執行緒堆棧等資訊。就是可能查看起來不太直觀。訪問 http://localhost:8080/actuator/threaddump
返回如下:

5.8 /shutdown
端點
這個端點屬於操作控制類端點,可以優雅關閉 Spring Boot 應用。要使用這個功能首先需要在配置文件中開啟:
management.endpoint.shutdown.enabled=true
由於 shutdown 介面默認只支援 POST 請求,我們啟動Demo項目,向 http://localhost:8080/actuator/shutdown
發起 POST
請求。返回資訊:
{ "message": "Shutting down, bye..." }
然後應用程式被關閉。
由於開放關閉應用的操作本身是一件非常危險的事,所以真正在線上使用的時候,我們需要對其加入一定的保護機制,比如:訂製Actuator的端點路徑、整合Spring Security進行安全校驗等。(不是特別必要的話,這個端點不用開)
六、整合Spring Security 對端點進行安全校驗
由於端點的資訊和產生的交互都是非常敏感的,必須防止未經授權的外部訪問。如果您的應用程式中存在Spring Security的依賴,則默認情況下使用基於表單的HTTP身份驗證來保護端點。
如果沒有,只需要增加對應的依賴即可:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
添加之後,我們需要定義安全校驗規則,來覆蓋Spring Security 的默認配置。
這裡我給出了兩個版本的模板配置:
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest; import org.springframework.boot.actuate.context.ShutdownEndpoint; import org.springframework.boot.autoconfigure.security.servlet.PathRequest; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; /** * @author Richard_yyf */ @Configuration public class ActuatorSecurityConfig extends WebSecurityConfigurerAdapter { /* * version1: * 1. 限制 '/shutdown'端點的訪問,只允許ACTUATOR_ADMIN訪問 * 2. 允許外部訪問其他的端點 * 3. 允許外部訪問靜態資源 * 4. 允許外部訪問 '/' * 5. 其他的訪問需要被校驗 * version2: * 1. 限制所有端點的訪問,只允許ACTUATOR_ADMIN訪問 * 2. 允許外部訪問靜態資源 * 3. 允許外部訪問 '/' * 4. 其他的訪問需要被校驗 */ @Override protected void configure(HttpSecurity http) throws Exception { // version1 // 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(); // version2 http .authorizeRequests() .requestMatchers(EndpointRequest.toAnyEndpoint()) .hasRole("ACTUATOR_ADMIN") .requestMatchers(PathRequest.toStaticResources().atCommonLocations()) .permitAll() .antMatchers("/") .permitAll() .antMatchers("/**") .authenticated() .and() .httpBasic(); } }
application.properties
的相關配置如下:
# Spring Security Default user name and password spring.security.user.name=actuator spring.security.user.password=actuator spring.security.user.roles=ACTUATOR_ADMIN
結語
本篇文章內容就到這裡。
對應的源碼可以Github上看到。
https://github.com/Richard-yyf/springboot-actuator-prometheus-test
如果本文有幫助到你,希望能點個贊,這是對我的最大動力????。
參考
https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html
http://www.ityouknow.com/springboot/2018/02/06/spring-boot-actuator.html
作者:Richard_Yi
來源:juejin.im/post/5e2179def265da3e152d2561
其它優質文章請見後台公眾號菜單