1. 引言
在當前的微服務架構方式下,我們會有很多的服務部署在不同的機器上,相互是通過服務調用的方式進行交互,一個完整的業務流程中間會經過很多個微服務的處理和傳遞,那么,如何能知道每個服務的健康狀況就顯得尤為重要。
萬幸的是 Spring Boot 為我們提供了監控模塊 Spring Boot Actuator ,本篇文章將和大家一起探討一些 Spring Boot Actuator 一些常見用法方便我們在日常的使用中對我們的微服務進行監控治理。
Spring Boot Actuator 幫我們實現了對程序內部運行情況監控,比如監控狀況、Bean加載情況、環境變量、日志信息、線程信息等。
2. Actuator 的使用
2.1 工程依賴
使用 Spring Boot Actuator 需要加入如下依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
注意: 因 Spring Boot Actuator 會暴露我們服務的詳細信息,為了保障安全性,建議添加安全控制的相關依賴 spring-boot-starter-security
,這樣,在訪問應用監控端點時,都需要輸入驗證信息。所需依賴如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2.2 工程配置
配置文件 application.yml 如下:
代碼清單:spring-boot-actuator/src/main/resources/application.yml
server:
port: 8080
info:
app:
name: spring-boot-actuator
version: 1.0.0
spring:
security:
user:
name: admin
password: admin
現在先啟動工程,打開瀏覽器訪問:http://localhost:8080/actuator ,可以看到頁面顯示如下 json :
{
"_links":{
"self":{
"href":"http://localhost:8080/actuator",
"templated":false
},
"health":{
"href":"http://localhost:8080/actuator/health",
"templated":false
},
"health-component-instance":{
"href":"http://localhost:8080/actuator/health/{component}/{instance}",
"templated":true
},
"health-component":{
"href":"http://localhost:8080/actuator/health/{component}",
"templated":true
},
"info":{
"href":"http://localhost:8080/actuator/info",
"templated":false
}
}
}
這些是默認支持的鏈接,只有:
/actuator
/actuator/health
/health/{component}/{instance}
/health/{component}
/actuator/info
我們可以在配置文件 application.yml 中增加配置來開啟更多的監控信息:
management:
endpoints:
web:
exposure:
include: '*'
# base-path: /monitor
endpoint:
health:
show-details: always
shutdown:
enabled: true
management.endpoints.web.exposure.include='*'
代表開啟全部監控,當然也可以配置需要開啟的監控,如:management.endpoints.web.exposure.include=beans,trace
。management.endpoint.health.show-details=always
含義是 health endpoint 是開啟顯示全部細節。默認情況下, /actuator/health 是公開的,並且不顯示細節。management.endpoints.web.base-path=/monitor
代表啟用單獨的url地址來監控 Spring Boot 應用,默認的路徑是/actuator/*
,如果開啟此配置,重啟后再次訪問路徑就會變成/manage/*
。management.endpoint.shutdown.enabled=true
啟用接口關閉 Spring Boot 。
在某些業務場景下,我們的監控信息可能會需要跨越獲取, Spring Boot Actuator 提供了 CORS 相關的配置,來支持跨域調用,默認情況下,CORS 支持處於禁用狀態,只有在設置了 management.endpoints.web.cors.allowed-origins
屬性后才能啟用。以下配置允許來自 https://www.geekdigging.com
域的 GET 和 POST 調用:
management:
endpoints:
web:
cors:
allowed-origins: https://www.geekdigging.com
allowed-methods: GET,POST
2.3 REST 接口
Spring Boot Actuator 為我們提供了非常豐富的監控接口,可以通過它們了解應用程序運行時的內部狀況。同時 Actuator 支持用戶自定義添加端點,用戶可以根據自己的實際應用,定義一些比較關心的指標,在運行期進行監控。
HTTP 方法 | 路徑 | 描述 |
---|---|---|
GET | /auditevents | 顯示當前應用程序的審計事件信息 |
GET | /beans | 顯示一個應用中所有Spring Beans的完整列表 |
GET | /conditions | 顯示配置類和自動配置類(configuration and auto-configuration classes)的狀態及它們被應用或未被應用的原因 |
GET | /configprops | 顯示一個所有@ConfigurationProperties的集合列表 |
GET | /env | 顯示來自Spring的 ConfigurableEnvironment的屬性 |
GET | /flyway | 顯示數據庫遷移路徑,如果有的話 |
GET | /health | 顯示應用的健康信息(當使用一個未認證連接訪問時顯示一個簡單的’status’,使用認證連接訪問則顯示全部信息詳情) |
GET | /info | 顯示任意的應用信息 |
GET | /liquibase | 展示任何Liquibase數據庫遷移路徑,如果有的話 |
GET | /metrics | 展示當前應用的metrics信息 |
GET | /mappings | 顯示一個所有@RequestMapping路徑的集合列表 |
GET | /scheduledtasks | 顯示應用程序中的計划任務 |
GET | /sessions | 允許從Spring會話支持的會話存儲中檢索和刪除(retrieval and deletion)用戶會話。使用Spring Session對反應性Web應用程序的支持時不可用。 |
POST | /shutdown | 允許應用以優雅的方式關閉(默認情況下不啟用) |
GET | /threaddump | 執行一個線程dump |
如果使用web應用(Spring MVC, Spring WebFlux, 或者 Jersey),還可以使用以下接口:
HTTP 方法 | 路徑 | 描述 |
---|---|---|
GET | /heapdump | 返回一個GZip壓縮的hprof堆dump文件 |
GET | /jolokia | 通過HTTP暴露JMX beans(當Jolokia在類路徑上時,WebFlux不可用) |
GET | /logfile | 返回日志文件內容(如果設置了logging.file或logging.path屬性的話),支持使用HTTP Range頭接收日志文件內容的部分信息 |
GET | /prometheus | 以可以被Prometheus服務器抓取的格式顯示metrics信息 |
3. 接口詳解
3.1 /health
health 主要用來檢查應用的運行狀態,這是我們使用最高頻的一個監控點。通常使用此接口提醒我們應用實例的運行狀態,以及應用不”健康“的原因,比如數據庫連接、磁盤空間不夠等。
默認情況下 health 的狀態是開放的,添加依賴后啟動項目,訪問:http://localhost:8080/actuator/health 即可看到應用的狀態。
{
"status" : "UP"
}
默認情況下,最終的 Spring Boot 應用的狀態是由 HealthAggregator
匯總而成的,匯總的算法是:
- 設置狀態碼順序:
setStatusOrder(Status.DOWN, Status.OUT_OF_SERVICE, Status.UP, Status.UNKNOWN);
。 - 過濾掉不能識別的狀態碼。
- 如果無任何狀態碼,整個 Spring Boot 應用的狀態是 UNKNOWN。
- 將所有收集到的狀態碼按照 1 中的順序排序。
- 返回有序狀態碼序列中的第一個狀態碼,作為整個 Spring Boot 應用的狀態。
Health 通過合並幾個健康指數檢查應用的健康情況。Spring Boot Actuator 會自動配置以下內容:
名稱 | 描述 |
---|---|
CassandraHealthIndicator | 檢查Cassandra數據庫是否已啟動。 |
CouchbaseHealthIndicator | 檢查Couchbase群集是否已啟動。 |
DiskSpaceHealthIndicator | 檢查磁盤空間不足。 |
DataSourceHealthIndicator | 檢查是否可以建立連接 DataSource 。 |
ElasticsearchHealthIndicator | 檢查Elasticsearch集群是否已啟動。 |
InfluxDbHealthIndicator | 檢查InfluxDB服務器是否已啟動。 |
JmsHealthIndicator | 檢查JMS代理是否啟動。 |
MailHealthIndicator | 檢查郵件服務器是否已啟動。 |
MongoHealthIndicator | 檢查Mongo數據庫是否已啟動。 |
Neo4jHealthIndicator | 檢查Neo4j服務器是否已啟動。 |
RabbitHealthIndicator | 檢查Rabbit服務器是否已啟動。 |
RedisHealthIndicator | 檢查Redis服務器是否啟動。 |
SolrHealthIndicator | 檢查Solr服務器是否已啟動。 |
可以通過設置 management.health.defaults.enabled
屬性來全部禁用它們。
3.2 /info
info 就是我們自己在配置文件中配置的以 info 開頭的信息,如我們在示例工程中配置的:
info:
app:
name: spring-boot-actuator
version: 1.0.0
啟動工程,打開瀏覽器訪問: http://localhost:8080/actuator/info
,結果如下:
{
"app":{
"name":"spring-boot-actuator",
"version":"1.0.0"
}
}
3.3 /beans
啟動工程,打開瀏覽器訪問: http://localhost:8080/actuator/beans
,部分結果如下:
{
"contexts": {
"application": {
"beans": {
"endpointCachingOperationInvokerAdvisor": {
"aliases": [],
"scope": "singleton",
"type": "org.springframework.boot.actuate.endpoint.invoker.cache.CachingOperationInvokerAdvisor",
"resource": "class path resource [org/springframework/boot/actuate/autoconfigure/endpoint/EndpointAutoConfiguration.class]",
"dependencies": ["environment"]
},
"defaultServletHandlerMapping": {
"aliases": [],
"scope": "singleton",
"type": "org.springframework.web.servlet.HandlerMapping",
"resource": "class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]",
"dependencies": []
},
},
"parentId": null
}
}
}
從中可以看到,這個接口展現了 bean 的別名、類型、是否單例、類的地址、依賴等信息。
3.4 /conditions
啟動工程,打開瀏覽器訪問: http://localhost:8080/actuator/conditions
,部分結果如下:
{
"contexts": {
"application": {
"positiveMatches": {
"AuditAutoConfiguration#auditListener": [{
"condition": "OnBeanCondition",
"message": "@ConditionalOnMissingBean (types: org.springframework.boot.actuate.audit.listener.AbstractAuditListener; SearchStrategy: all) did not find any beans"
}],
"AuditAutoConfiguration#authenticationAuditListener": [{
"condition": "OnClassCondition",
"message": "@ConditionalOnClass found required class 'org.springframework.security.authentication.event.AbstractAuthenticationEvent'"
}, {
"condition": "OnBeanCondition",
"message": "@ConditionalOnMissingBean (types: org.springframework.boot.actuate.security.AbstractAuthenticationAuditListener; SearchStrategy: all) did not find any beans"
}],
},
}
}
}
是用這個接口可以看出應用運行時查看代碼了某個配置在什么條件下生效,或者某個自動配置為什么沒有生效。
3.5 /shutdown
這個接口首先需要在配置文件中配置開啟此功能:
management.endpoint.shutdown.enabled=true
配置完成后,可以使用 curl 模擬 post 請求此接口:
curl -X POST "http://localhost:8080/actuator/shutdown"
顯示結果為:
{
"message": "Shutting down, bye..."
}
注意:示例工程添加了 spring-boot-starter-security
,直接使用 post 訪問此接口會響應 401 ,表示無權限訪問,如需測試此接口,請暫時先關閉 spring-boot-starter-security
。
這時可以看到我們啟動的示例工程已經關閉了。
3.6 /mappings
描述全部的 URI 路徑,以及它們和控制器的映射關系
啟動工程,打開瀏覽器訪問: http://localhost:8080/actuator/mappings
,部分結果如下:
{
"handler": "Actuator web endpoint 'beans'",
"predicate": "{GET /actuator/beans, produces [application/vnd.spring-boot.actuator.v2+json || application/json]}",
"details": {
"handlerMethod": {
"className": "org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping.OperationHandler",
"name": "handle",
"descriptor": "(Ljavax/servlet/http/HttpServletRequest;Ljava/util/Map;)Ljava/lang/Object;"
},
"requestMappingConditions": {
"consumes": [],
"headers": [],
"methods": ["GET"],
"params": [],
"patterns": ["/actuator/beans"],
"produces": [{
"mediaType": "application/vnd.spring-boot.actuator.v2+json",
"negated": false
}, {
"mediaType": "application/json",
"negated": false
}]
}
}
}
3.7 /threaddump
/threaddump 接口會生成當前線程活動的快照。這個功能非常好,方便我們在日常定位問題的時候查看線程的情況。 主要展示了線程名、線程ID、線程的狀態、是否等待鎖資源等信息。
啟動工程,打開瀏覽器訪問: http://localhost:8080/actuator/threaddump
,部分結果如下:
{
"threads": [{
"threadName": "Reference Handler",
"threadId": 2,
"blockedTime": -1,
"blockedCount": 2,
"waitedTime": -1,
"waitedCount": 0,
"lockName": null,
"lockOwnerId": -1,
"lockOwnerName": null,
"daemon": true,
"inNative": false,
"suspended": false,
"threadState": "RUNNABLE",
"priority": 10,
"stackTrace": [{
"classLoaderName": null,
"moduleName": "java.base",
"moduleVersion": "11.0.4",
"methodName": "waitForReferencePendingList",
"fileName": "Reference.java",
"lineNumber": -2,
"className": "java.lang.ref.Reference",
"nativeMethod": true
}
...
"lockedMonitors": [],
"lockedSynchronizers": [{
"className": "java.util.concurrent.locks.ReentrantLock$NonfairSync",
"identityHashCode": 2060076420
}],
"lockInfo": null
...
{
"threadName": "DestroyJavaVM",
"threadId": 42,
"blockedTime": -1,
"blockedCount": 0,
"waitedTime": -1,
"waitedCount": 0,
"lockName": null,
"lockOwnerId": -1,
"lockOwnerName": null,
"daemon": false,
"inNative": false,
"suspended": false,
"threadState": "RUNNABLE",
"priority": 5,
"stackTrace": [],
"lockedMonitors": [],
"lockedSynchronizers": [],
"lockInfo": null
}]
}