1. 程式人生 > 程式設計 >Spring Boot應用的健康監控

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檔案中進行一定的配置,首先在節點裡面新增:
<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