微服務的特點決定了功能模塊的部署是分布式的,大部分功能模塊都是運行在不同的機器上,彼此通過服務調用進行交互,前后台的業務流會經過很多個微服務的處理和傳遞,出現了異常如何快速定位是哪個環節出現了問題?
在這種框架下,微服務的監控顯得尤為重要。本文主要結合 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 打開此文件查看內存快照。類似如下圖:
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
參考
Spring Boot Actuator: Production-ready features
對沒有監控的微服務Say No!
Spring Boot Actuator 使用