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

Spring Boot應用的健康監控

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

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

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

How Do

  • 在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[email protected]@
    info.build.name[email protected]@
    info.build.description[email protected]@
    info.build.version[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>
  • 除了使用系統預設的監控資訊,我們還可以定義自己的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;
    }

自定義的health indicator

分析

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

  • /env提供應用程式的環境變數,如果你在除錯時想知道某個配置項在執行時的值,可以通過這個endpoint訪問——訪問,可以看到很多方面的配置,例如,class path resources—[tomcat.https.properties]、applicationConfig—[classpath:/application.properties]、commonsConfig、systemEnvironment、systemProperties等。
    這些變數的值由Environment例項中的PropertySource例項儲存,根據這些屬性值所在的層次,有可能在執行時已經做了值替換,跟配置檔案中的不一樣了。為了確認某個屬性的具體值,例如book.count.rate屬性,可以訪問來查詢,如果跟配置檔案中的不一樣,則可能是被系統變數或者命令列引數覆蓋了。EnvironmentEndpoint類負責實現上述功能,有興趣可以再看看它的原始碼;
  • /configprops提供不同配置物件,例如WebConfiguration.TomcatSslConnectionProperties,它與/env不同的地方在於它會表示出與配置項繫結的物件。嘗試下訪問,然後在網頁中查詢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.開頭的屬性都會在訪問時顯示。
  • /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,可以設定指定的根路徑。綜合下,經過上述設定,在本地訪問來訪問健康狀態。

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

參考資料