Spring Boot Actuator 模塊 詳解:健康檢查,度量,指標收集和監控

image

前言

去年我們項目做了微服務1.0的架構轉型,但是服務監控這塊卻沒有跟上。這不,最近我就被分配了要將我們核心的微服務應用全部監控起來的任務。我們的微服務應用都是SpringBoot 應用,因此就自然而然的想到了借助Spring Boot 的Actuator 模塊。(沒吃過豬肉總聽過豬叫見過豬跑吧??)。

本篇是我在完成這個工單之后,對Spring Boot Actuator模塊 學習應用的總結。在本篇文章中,你可以學習到:

  • Spring Boot Actuator 的快速使用入門
  • Spring Boot Actuator 的一些重要的endpoints的介紹
  • 如何通過Actuator 模塊實時查看當前應用的線程 dump信息
  • 如何通過Actuator 模塊實時查看當前應用的堆信息
  • 如何通過Actuator 模塊實時修改當前應用的日志打印登記
  • ...

之后我還會介紹:

  • TODO:SpringBoot 微服務應用集成Prometheus + Grafana實現監控告警

一、什么是 Spring Boot Actuator

Spring Boot Actuator 模塊提供了生產級別的功能,比如健康檢查,審計,指標收集,HTTP 跟蹤等,幫助我們監控和管理Spring Boot 應用。這個模塊是一個采集應用內部信息暴露給外部的模塊,上述的功能都可以通過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
image
  • 對應的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請求統計等。
  • 操作控制類:提供了對應用的關閉等操作類功能。

詳細的原生端點介紹,請以官網為準,這里就不贅述徒增篇幅。

需要注意的就是:

  • 每一個端點都可以通過配置來單獨禁用或者啟動
  • 不同于Actuator 1.x,Actuator 2.x 的大多數端點默認被禁掉。 Actuator 2.x 中的默認端點增加了/actuator前綴。默認暴露的兩個端點為/actuator/health/actuator/info

四、端點暴露配置

我們可以通過以下配置,來配置通過JMX 和 HTTP 暴露的端點。

Property Default
management.endpoints.jmx.exposure.exclude
management.endpoints.jmx.exposure.include *
management.endpoints.web.exposure.exclude
management.endpoints.web.exposure.include info, healt

可以打開所有的監控點

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,查看暴露出來的端點:

image

上面這樣顯示是因為chrome 瀏覽器安裝了 JSON-handle 插件,實際上就是返回一大段json

下面,我會著重介紹幾個比較重要的端點。

五、重要端點解析

5.1 /health端點

/health端點會聚合你程序的健康指標,來檢查程序的健康情況。端點公開的應用健康信息取決于:

management.endpoint.health.show-details=always

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

Name Description
never 不展示詳細信息,up或者down的狀態,默認配置
when-authorized 詳細信息將會展示給通過認證的用戶。授權的角色可以通過management.endpoint.health.roles配置
always 對所有用戶暴露詳細信息

按照上述配置,配置成always之后,我們啟動項目,訪問http://localhost:8080/actuator/health端口,可以看到這樣的信息:

image

是不是感覺好像健康信息有點少?先別急,那是因為我們創建的是一個最基礎的Demo項目,沒有依賴很多的組件。

/health端點有很多自動配置的健康指示器:如redis、rabbitmq、db等組件。當你的項目有依賴對應組件的時候,這些健康指示器就會被自動裝配,繼而采集對應的信息。如上面的 diskSpace 節點信息就是DiskSpaceHealthIndicator 在起作用。

image

上述截圖取自官方文檔

這是我另一個項目的/health端點信息。

image

當如上的組件有一個狀態異常,應用服務的整體狀態即為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");
    }
}

最終效果:

image

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,返回信息如下:

image

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

image

5.3/loggers端點

/loggers 端點暴露了我們程序內部配置的所有logger的信息。我們訪問/actuator/loggers可以看到,

image

你也可以通過下述方式訪問單獨一個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/rootPOST請求,POST報文如下:

{
   "configuredLevel": "DEBUG"
}
image

仔細想想,這個功能是不是非常有用。如果在生產環境中,你想要你的應用輸出一些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的值
# info.app.encoding=@project.build.sourceEncoding@
# info.app.java.source=@java.version@
# info.app.java.target=@java.version@

啟動項目,訪問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,返回如下:

image

5.6 /heapdump 端點

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

image

5.7 /threaddump 端點

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

image

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上看到。

如果本文有幫助到你,希望能點個贊,這是對我的最大動力????????。

參考

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,663評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,125評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,506評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,614評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,402評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,934評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,021評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,168評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,690評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,596評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,288評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,027評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,404評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,662評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,398評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,743評論 2 370

推薦閱讀更多精彩內容