Spring Boot應用的健康監控

本文首發於個人網站:Spring Boot應用的健康監控

在之前的系列文章中我們學習瞭如何進行Spring Boot應用的功能開發,以及如何寫單元測試、集成測試等,然而,在實際的軟件開發中需要做的不僅如此:還包括對應用程序的監控和管理。

正如飛行員不喜歡盲目飛行,程序員也需要實時看到自己的應用目前的運行情況。如果給定一個具體的時間,我們希望知道此時CPU的利用率、內存的利用率、數據庫連接是否正常以及在給定時間段內有多少客戶請求等指標;不僅如此,我們希望通過圖表、控制面板來展示上述信息。最重要的是:老闆和業務人員希望看到的是圖表,這些比較直觀易懂。

首先,這篇文章講介紹如何定製自己的health indicator。

實戰

  • 在pom文件中添加spring-boot-starter-actuator依賴
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
  • spring-boot-starter-actuator這個庫讓我們可以訪問應用的很多信息,包括:/env、/info、/metrics、/health等。現在運行程序,然後在瀏覽器中訪問:http://localhost:8080/health,將可以看到下列內容。acatuator庫提供監控信息
  • 除了/health可以訪問,其他的Endpoints也可以訪問,例如/info:首先在application.properties文件中添加對應的屬性值,符號@包圍的屬性值來自pom.xml文件中的元素節點。
[email protected]@
[email protected]@
[email protected]@
[email protected]@
  • 要獲取配置文件中的節點值,需要在pom文件中進行一定的配置,首先在<build>節點裏面添加:
<resources>
   <resource>
      <directory>src/main/resources</directory>
      <filtering>true</filtering>
   </resource>
</resources>

然後在<plugins>節點裏面增加對應的插件:

<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-resources-plugin</artifactId>
   <version>2.6</version>
   <configuration>
      <delimiters>
         <delimiter>@</delimiter>
      </delimiters>
      <useDefaultDelimiters>false</useDefaultDelimiters>
   </configuration>
</plugin>
  • 然後運行應用程序,訪問http://localhost:8080/info,可以看到下列信息
    http://localhost:8080/info
  • 除了使用系統默認的監控信息,我們還可以定義自己的health indicator。使用Spring Boot:定製自己的starter一文中做過的db-count-starter作爲觀察對象,我們希望監控每個數據庫接口的運行狀況:如果某個接口返回的個數大於等於0,則表示系統正常,表示爲UP狀態;否則,可能該接口發生異常,表示爲DOWN狀態。首先,將DbCountRunner類中的getRepositoryName方法由private轉爲protected,然後在db-count-starter這個模塊中也添加actuator依賴。
  • db-count-starter/src/main/com/test/bookpubstarter目錄下創建DbCountHealthIndicator.java文件
public class DbCountHealthIndicator implements HealthIndicator {
    private CrudRepository crudRepository;
    public DbCountHealthIndicator(CrudRepository crudRepository) {
        this.crudRepository = crudRepository;
    }
    @Override
    public Health health() {
        try {
            long count = crudRepository.count();
            if (count >= 0) {
                return Health.up().withDetail("count", count).build();
            } else {
                return Health.unknown().withDetail("count", count).build();
            }
        } catch (Exception e) {
            return Health.down(e).build();
        }
    }
}
  • 最後,還需要註冊剛剛創建的健康監控器,在DbCountAutoConfiguration.java中增加如下定義:
@Autowired
private HealthAggregator healthAggregator;
@Bean
public HealthIndicator dbCountHealthIndicator(Collection<CrudRepository> repositories) {
    CompositeHealthIndicator compositeHealthIndicator = new
            CompositeHealthIndicator(healthAggregator);
    for (CrudRepository repository: repositories) {
        String name = DbCountRunner.getRepositoryName(repository.getClass());
        compositeHealthIndicator.addHealthIndicator(name, new DbCountHealthIndicator(repository));
    }
    return compositeHealthIndicator;
}
  • 運行程序,然後訪問http://localhost:8080/health,則可以看到如下結果

自定義的health indicator

分析

Spring Boot Autuator這個庫包括很多自動配置,對外開放了很多endpoints,通過這些endpoints可以訪問應用的運行時狀態:

  • /env提供應用程序的環境變量,如果你在調試時想知道某個配置項在運行時的值,可以通過這個endpoint訪問——訪問http://localhost:8080/env,可以看到很多方面的配置,例如,class path resources—[tomcat.https.properties]、applicationConfig—[classpath:/application.properties]、commonsConfig、systemEnvironment、systemProperties等。
    這些變量的值由Environment實例中的PropertySource實例保存,根據這些屬性值所在的層次,有可能在運行時已經做了值替換,跟配置文件中的不一樣了。爲了確認某個屬性的具體值,例如book.count.rate屬性,可以訪問http://localhost:8080/env/book.counter.rate來查詢,如果跟配置文件中的不一樣,則可能是被系統變量或者命令行參數覆蓋了。EnvironmentEndpoint類負責實現上述功能,有興趣可以再看看它的源碼;
  • /configprops提供不同配置對象,例如WebConfiguration.TomcatSslConnectionProperties,它與/env不同的地方在於它會表示出與配置項綁定的對象。嘗試下訪問http://localhost:8080/configprops,然後在網頁中查詢custom.tomcat.https,可以看到我們之前用於配置TomcatSslConnector對象的屬性值(參見:讓你的Spring Boot工程支持HTTP和HTTPS)。
    TomcatSslConnector對應的屬性值
  • /autoconfig以web形式對外暴露AutoConfiguration 信息,這些信息的解釋可以參考Spring Boot:定製自己的starter一文,這樣我們就不需要通過“修改應用程序的日誌級別和查看應用的啓動信息”來查看應用的自動配置情況了。
  • /beans,這個endpoint列出所有由Spring Boot創建的bean。
    /beans顯示所有Spring Boot創建的bean
  • /mapping,這個endpoint顯示當前應用支持的URL映射,該映射關係由HandlerMapping類維護,通過這個endpoint可以查詢某個URL的路由信息。
    /mappings查看URL映射
  • /info,這個endpoint顯示應用程序的基本描述,在之前的實踐例子中我們看過它的返回信息,屬性值來自appliaction.properties,同時也可以使用佔位符獲取pom.xml文件中的信息。任何以info.開頭的屬性都會在訪問http://localhost:8080/info時顯示。
  • /health提供應用程序的健康狀態,或者是某個核心模塊的健康狀態。
  • /metrics,這個endpoint顯示Metrics 子系統管理的信息,後面的文章會詳細介紹它。

上述各個endpoint是Spring Boot Actuator提供的接口和方法,接下來看看我們自己定製的HealthIndicator,我們只需要實現HealthIndicator接口,Spring Boot會收集該接口的實現,並加入到/health這個endpoint中。

在我們的例子中,我們爲每個CrudRepository實例都創建了一個HealthIndicator實例,爲此我們創建了一個CompositeHealthIndicator實例,由這個實例管理所有的DbHealthIndicator實例。作爲一個composite,它會提供一個內部的層次關係,從而可以返回JSON格式的數據。

代碼中的HealthAggregator實例的作用是:它維護一個map,告訴CompositeHealthIndicator如何決定所有HealthIndicator代表的整體的狀態。例如,除了一個repository返回DOWN其他的都返回UP,這時候這個composite indicator作爲一個整體應該返回UP還是DOWN,HealthAggregator實例的作用就在這裏。

Spring Boot使用的默認的HealthAggregator實現是OrderedHealthAggregator,它的策略是手機所有的內部狀態,然後選出在DOWN、OUT_OF_SERVICE、UP和UNKNOWN中間具有最低優先級的那個狀態。這裏使用策略設計模式,因此具體的狀態判定策略可以改變和定製,例如我們可以創建定製的HealthAggregator

最後需要考慮下安全問題,通過這些endpoints暴露出很多應用的信息,當然,Spring Boot也提供了配置項,可以關閉指定的endpoint——在application.properties中配置<name>.enable=false

還可以通過設置management.port=-1關閉endpoint的HTTP訪問接口,或者是設置其他的端口,供內部的admin服務訪問;除了控制端口,還可以設置僅僅讓本地訪問,只需要設置management.address=127.0.0.1;通過設置management.context-path=/admin,可以設置指定的根路徑。綜合下,經過上述設置,在本地訪問http://127.0.0.1/admin/health來訪問健康狀態。

可以在防火牆上屏蔽掉不是/admin/*的endpoints訪問請求,更進一步,利用Spring Security可以配置驗證信息,這樣要訪問當前應用的endpoints必須使用用戶名和密碼登陸。

參考資料

  1. Endpoints
  2. Complete Guide for Spring Boot Actuator

Spring Boot 1.x系列

  1. Spring Boot的自動配置、Command-line-Runner
  2. 瞭解Spring Boot的自動配置
  3. Spring Boot的@PropertySource註解在整合Redis中的使用
  4. Spring Boot項目中如何定製HTTP消息轉換器
  5. Spring Boot整合Mongodb提供Restful接口
  6. Spring中bean的scope
  7. Spring Boot項目中使用事件派發器模式
  8. Spring Boot提供RESTful接口時的錯誤處理實踐
  9. Spring Boot實戰之定製自己的starter
  10. Spring Boot項目如何同時支持HTTP和HTTPS協議
  11. 自定義的Spring Boot starter如何設置自動配置註解
  12. Spring Boot項目中使用Mockito
  13. 在Spring Boot項目中使用Spock測試框架
  14. Spring Boot項目中如何定製攔截器
  15. Spring Boot項目中如何定製PropertyEditors
  16. Spring Boot構建的Web項目如何在服務端校驗表單輸入

本號專注於後端技術、JVM問題排查和優化、Java面試題、個人成長和自我管理等主題,爲讀者提供一線開發者的工作和成長經驗,期待你能在這裏有所收穫。
javaadu

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