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文件中的元素節點。
info.build.artifact=@project.artifactId@
info.build.name=@project.name@
info.build.description=@project.description@
info.build.version=@project.version@
  • 要獲取配置文件中的節點值,需要在pom文件中進行一定的配置,首先在 節點里面添加:
<resources>
   <resource>
      <directory>src/main/resources</directory>
      <filtering>true</filtering>
   </resource>
</resources>

然后在 節點里面增加對應的插件:

<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中配置 .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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM