Spring Boot (十九):使用 Spring Boot Actuator 監控應用

純潔的微笑發表於2018-02-06

微服務的特點決定了功能模組的部署是分散式的,大部分功能模組都是執行在不同的機器上,彼此通過服務呼叫進行互動,前後臺的業務流會經過很多個微服務的處理和傳遞,出現了異常如何快速定位是哪個環節出現了問題?

在這種框架下,微服務的監控顯得尤為重要。本文主要結合 Spring Boot Actuator,跟大家一起分享微服務 Spring Boot Actuator 的常見用法,方便我們在日常中對我們的微服務進行監控治理。

Actuator 監控

Spring Boot 使用“習慣優於配置的理念”,採用包掃描和自動化配置的機制來載入依賴 Jar 中的 Spring bean,不需要任何 Xml 配置,就可以實現 Spring 的所有配置。雖然這樣做能讓我們的程式碼變得非常簡潔,但是整個應用的例項建立和依賴關係等資訊都被離散到了各個配置類的註解上,這使得我們分析整個應用中資源和例項的各種關係變得非常的困難。

Actuator 是 Spring Boot 提供的對應用系統的自省和監控的整合功能,可以檢視應用配置的詳細資訊,例如自動化配置資訊、建立的 Spring beans 以及一些環境屬性等。

為了保證 actuator 暴露的監控介面的安全性,需要新增安全控制的依賴spring-boot-start-security依賴,訪問應用監控端點時,都需要輸入驗證資訊。Security 依賴,可以選擇不加,不進行安全管理,但不建議這麼做。

Actuator 的 REST 介面

Actuator 監控分成兩類:原生端點和使用者自定義端點;自定義端點主要是指擴充套件性,使用者可以根據自己的實際應用,定義一些比較關心的指標,在執行期進行監控。

原生端點是在應用程式裡提供眾多 Web 介面,通過它們瞭解應用程式執行時的內部狀況。原生端點又可以分成三類:

  • 應用配置類:可以檢視應用在執行期的靜態資訊:例如自動配置資訊、載入的 springbean 資訊、yml 檔案配置資訊、環境資訊、請求對映資訊;
  • 度量指標類:主要是執行期的動態資訊,例如堆疊、請求連、一些健康指標、metrics 資訊等;
  • 操作控制類:主要是指 shutdown,使用者可以傳送一個請求將應用的監控功能關閉。

Actuator 提供了 13 個介面,具體如下表所示。

HTTP 方法 路徑 描述
GET /auditevents 顯示應用暴露的審計事件 (比如認證進入、訂單失敗)
GET /beans 描述應用程式上下文裡全部的 Bean,以及它們的關係
GET /conditions 就是 1.0 的 /autoconfig ,提供一份自動配置生效的條件情況,記錄哪些自動配置條件通過了,哪些沒通過
GET /configprops 描述配置屬性(包含預設值)如何注入Bean
GET /env 獲取全部環境屬性
GET /env/{name} 根據名稱獲取特定的環境屬性值
GET /flyway 提供一份 Flyway 資料庫遷移資訊
GET /liquidbase 顯示Liquibase 資料庫遷移的纖細資訊
GET /health 報告應用程式的健康指標,這些值由 HealthIndicator 的實現類提供
GET /heapdump dump 一份應用的 JVM 堆資訊
GET /httptrace 顯示HTTP足跡,最近100個HTTP request/repsponse
GET /info 獲取應用程式的定製資訊,這些資訊由info打頭的屬性提供
GET /logfile 返回log file中的內容(如果 logging.file 或者 logging.path 被設定)
GET /loggers 顯示和修改配置的loggers
GET /metrics 報告各種應用程式度量資訊,比如記憶體用量和HTTP請求計數
GET /metrics/{name} 報告指定名稱的應用程式度量值
GET /scheduledtasks 展示應用中的定時任務資訊
GET /sessions 如果我們使用了 Spring Session 展示應用中的 HTTP sessions 資訊
POST /shutdown 關閉應用程式,要求endpoints.shutdown.enabled設定為true
GET /mappings 描述全部的 URI路徑,以及它們和控制器(包含Actuator端點)的對映關係
GET /threaddump 獲取執行緒活動的快照

快速上手

相關配置

專案依賴

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
  </dependency>
</dependencies>

配置檔案

info.app.name=spring-boot-actuator
info.app.version= 1.0.0
info.app.test=test

management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always
#management.endpoints.web.base-path=/monitor

management.endpoint.shutdown.enabled=true
  • management.endpoints.web.base-path=/monitor 代表啟用單獨的url地址來監控 Spring Boot 應用,為了安全一般都啟用獨立的埠來訪問後端的監控資訊
  • management.endpoint.shutdown.enabled=true 啟用介面關閉 Spring Boot

配置完成之後,啟動專案就可以繼續驗證各個監控功能了。

命令詳解

在 Spring Boot 2.x 中為了安全期間,Actuator 只開放了兩個端點 /actuator/health/actuator/info。可以在配置檔案中設定開啟。

可以開啟所有的監控點

management.endpoints.web.exposure.include=*

也可以選擇開啟部分

management.endpoints.web.exposure.exclude=beans,trace

Actuator 預設所有的監控點路徑都在/actuator/*,當然如果有需要這個路徑也支援定製。

management.endpoints.web.base-path=/manage

設定完重啟後,再次訪問地址就會變成/manage/*

Actuator 幾乎監控了應用涉及的方方面面,我們重點講述一些經常在專案中常用的命令。

health

health 主要用來檢查應用的執行狀態,這是我們使用最高頻的一個監控點。通常使用此介面提醒我們應用例項的執行狀態,以及應用不”健康“的原因,比如資料庫連線、磁碟空間不夠等。

預設情況下 health 的狀態是開放的,新增依賴後啟動專案,訪問:http://localhost:8080/actuator/health即可看到應用的狀態。

{
    "status" : "UP"
}

預設情況下,最終的 Spring Boot 應用的狀態是由 HealthAggregator 彙總而成的,彙總的演算法是:

  • 1 設定狀態碼順序:setStatusOrder(Status.DOWN, Status.OUT_OF_SERVICE, Status.UP, Status.UNKNOWN);
  • 2 過濾掉不能識別的狀態碼。
  • 3 如果無任何狀態碼,整個 Spring Boot 應用的狀態是 UNKNOWN。
  • 4 將所有收集到的狀態碼按照 1 中的順序排序。
  • 5 返回有序狀態碼序列中的第一個狀態碼,作為整個 Spring Boot 應用的狀態。

health 通過合併幾個健康指數檢查應用的健康情況。Spring Boot Actuator 有幾個預定義的健康指標比如DataSourceHealthIndicator, DiskSpaceHealthIndicator, MongoHealthIndicator, RedisHealthIndicator等,它使用這些健康指標作為健康檢查的一部分。

舉個例子,如果你的應用使用 Redis,RedisHealthindicator 將被當作檢查的一部分;如果使用 MongoDB,那麼MongoHealthIndicator 將被當作檢查的一部分。

可以在配置檔案中關閉特定的健康檢查指標,比如關閉 redis 的健康檢查:

management.health.redise.enabled=false

預設,所有的這些健康指標被當作健康檢查的一部分。

info

info 就是我們自己配置在配置檔案中以 info 開頭的配置資訊,比如我們在示例專案中的配置是:

info.app.name=spring-boot-actuator
info.app.version= 1.0.0
info.app.test= test

啟動示例專案,訪問:http://localhost:8080/actuator/info返回部分資訊如下:

{
  "app": {
    "name": "spring-boot-actuator",
    "version": "1.0.0",
    "test":"test"
  }
}

beans

根據示例就可以看出,展示了 bean 的別名、型別、是否單例、類的地址、依賴等資訊。

啟動示例專案,訪問:http://localhost:8080/actuator/beans返回部分資訊如下:

[
  {
    "context": "application:8080:management",
    "parent": "application:8080",
    "beans": [
      {
        "bean": "embeddedServletContainerFactory",
        "aliases": [
          
        ],
        "scope": "singleton",
        "type": "org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory",
        "resource": "null",
        "dependencies": [
          
        ]
      },
      {
        "bean": "endpointWebMvcChildContextConfiguration",
        "aliases": [
          
        ],
        "scope": "singleton",
        "type": "org.springframework.boot.actuate.autoconfigure.EndpointWebMvcChildContextConfiguration$$EnhancerBySpringCGLIB$$a4a10f9d",
        "resource": "null",
        "dependencies": [
          
        ]
      }
  }
]

conditions

Spring Boot 的自動配置功能非常便利,但有時候也意味著出問題比較難找出具體的原因。使用 conditions 可以在應用執行時檢視程式碼了某個配置在什麼條件下生效,或者某個自動配置為什麼沒有生效。

啟動示例專案,訪問:http://localhost:8080/actuator/conditions返回部分資訊如下:

{
    "positiveMatches": {
     "DevToolsDataSourceAutoConfiguration": {
            "notMatched": [
                {
                    "condition": "DevToolsDataSourceAutoConfiguration.DevToolsDataSourceCondition", 
                    "message": "DevTools DataSource Condition did not find a single DataSource bean"
                }
            ], 
            "matched": [ ]
        }, 
        "RemoteDevToolsAutoConfiguration": {
            "notMatched": [
                {
                    "condition": "OnPropertyCondition", 
                    "message": "@ConditionalOnProperty (spring.devtools.remote.secret) did not find property 'secret'"
                }
            ], 
            "matched": [
                {
                    "condition": "OnClassCondition", 
                    "message": "@ConditionalOnClass found required classes 'javax.servlet.Filter', 'org.springframework.http.server.ServerHttpRequest'; @ConditionalOnMissingClass did not find unwanted class"
                }
            ]
        }
    }
}

heapdump

返回一個 GZip 壓縮的 JVM 堆 dump

啟動示例專案,訪問:http://localhost:8080/actuator/heapdump會自動生成一個 Jvm 的堆檔案 heapdump,我們可以使用 JDK 自帶的 Jvm 監控工具 VisualVM 開啟此檔案檢視記憶體快照。類似如下圖:

Spring Boot (十九):使用 Spring Boot Actuator 監控應用

shutdown

開啟介面優雅關閉 Spring Boot 應用,要使用這個功能首先需要在配置檔案中開啟:

management.endpoint.shutdown.enabled=true

配置完成之後,啟動示例專案,使用 curl 模擬 post 請求訪問 shutdown 介面。

shutdown 介面預設只支援 post 請求。

curl -X POST "http://localhost:8080/actuator/shutdown" 
{
    "message": "Shutting down, bye..."
}

此時你會發現應用已經被關閉。

mappings

描述全部的 URI 路徑,以及它們和控制器的對映關係

啟動示例專案,訪問:http://localhost:8080/actuator/mappings返回部分資訊如下:

{
  "/**/favicon.ico": {
    "bean": "faviconHandlerMapping"
  },
  "{[/hello]}": {
    "bean": "requestMappingHandlerMapping",
    "method": "public java.lang.String com.neo.controller.HelloController.index()"
  },
  "{[/error]}": {
    "bean": "requestMappingHandlerMapping",
    "method": "public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)"
  }
}

threaddump

/threaddump 介面會生成當前執行緒活動的快照。這個功能非常好,方便我們在日常定位問題的時候檢視執行緒的情況。
主要展示了執行緒名、執行緒ID、執行緒的狀態、是否等待鎖資源等資訊。

啟動示例專案,訪問:http://localhost:8080/actuator/threaddump返回部分資訊如下:

[
  {
    "threadName": "http-nio-8088-exec-6",
    "threadId": 49,
    "blockedTime": -1,
    "blockedCount": 0,
    "waitedTime": -1,
    "waitedCount": 2,
    "lockName": "java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@1630a501",
    "lockOwnerId": -1,
    "lockOwnerName": null,
    "inNative": false,
    "suspended": false,
    "threadState": "WAITING",
    "stackTrace": [
      {
        "methodName": "park",
        "fileName": "Unsafe.java",
        "lineNumber": -2,
        "className": "sun.misc.Unsafe",
        "nativeMethod": true
      },
      ...
      {
        "methodName": "run",
        "fileName": "TaskThread.java",
        "lineNumber": 61,
        "className": "org.apache.tomcat.util.threads.TaskThread$WrappingRunnable",
        "nativeMethod": false
      }
      ...
    ],
    "lockInfo": {
      "className": "java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject",
      "identityHashCode": 372286721
    }
  }
  ...
]

生產出現問題的時候,可以通過應用的執行緒快照來檢測應用正在執行的任務。

文章內容已經升級到 Spring Boot 2.x

示例程式碼-github

示例程式碼-碼雲

參考

Spring Boot Actuator: Production-ready features
對沒有監控的微服務Say No!
Spring Boot Actuator 使用

相關文章