在Spring Boot的眾多Starter POMs中有一個特殊的模塊,它不同于其他模塊那樣大多用于開發業務功能或是連接一些其他外部資源。它完全是一個用于暴露自身信息的模塊,所以很明顯,它的主要作用是用于監控與管理,它就是:spring-boot-starter-actuator
。
spring-boot-starter-actuator
模塊的實現對于實施微服務的中小團隊來說,可以有效地減少監控系統在采集應用指標時的開發量。當然,它也并不是萬能的,有時候我們也需要對其做一些簡單的擴展來幫助我們實現自身系統個性化的監控需求。下面,在本文中,我們將詳解的介紹一些關于spring-boot-starter-actuator
模塊的內容,包括它的原生提供的端點以及一些常用的擴展和配置方式。
初識Actuator
下面,我們可以通過對快速入門中實現的Spring Boot應用增加spring-boot-starter-actuator
模塊功能,來對它有一個直觀的認識。
在現有的Spring Boot應用中引入該模塊非常簡單,只需要在pom.xml
的dependencies節點中,新增spring-boot-starter-actuator的依賴即可,具體如下:
1
2
3
4
|
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> |
通過增加該依賴之后,重新啟動應用。此時,我們可以在控制臺中看到如下圖所示的輸出:
上圖顯示了一批端點定義,這些端點并非我們自己在程序中創建,而是由spring-boot-starter-actuator
模塊根據應用依賴和配置自動創建出來的監控和管理端點。通過這些端點,我們可以實時的獲取應用的各項監控指標,比如:訪問/health端點,我們可以獲得如下返回的應用健康信息:
1
2
3
4
5
6
7
8
9
|
{ "status" : "UP" , "diskSpace" : { "status" : "UP" , "total" : 491270434816 , "free" : 383870214144 , "threshold" : 10485760 } } |
原生端點
通過在快速入門示例中添加spring-boot-starter-actuator
模塊,我們已經對它有了一個初步的認識。接下來,我們詳細介紹一下spring-boot-starter-actuator
模塊中已經實現的一些原生端點。如果根據端點的作用來說,我們可以原生端點分為三大類:
- 應用配置類:獲取應用程序中加載的應用配置、環境變量、自動化配置報告等與Spring Boot應用密切相關的配置類信息。
- 度量指標類:獲取應用程序運行過程中用于監控的度量指標,比如:內存信息、線程池信息、HTTP請求統計等。
- 操作控制類:提供了對應用的關閉等操作類功能。
下面我們來詳細了解一下這三類端點都分別可以為我們提供怎么樣的有用信息和強大功能,以及我們如何去擴展和配置它們。
應用配置類
由于Spring Boot為了改善傳統Spring應用繁雜的配置內容,采用了包掃描和自動化配置的機制來加載原本集中于xml文件中的各項內容。雖然這樣的做法,讓我們的代碼變得非常簡潔,但是整個應用的實例創建和依賴關系等信息都被離散到了各個配置類的注解上,這使得我們分析整個應用中資源和實例的各種關系變得非常的困難。而這類端點就可以幫助我們輕松的獲取一系列關于Spring 應用配置內容的詳細報告,比如:自動化配置的報告、Bean創建的報告、環境屬性的報告等。
- /autoconfig:該端點用來獲取應用的自動化配置報告,其中包括所有自動化配置的候選項。同時還列出了每個候選項自動化配置的各個先決條件是否滿足。所以,該端點可以幫助我們方便的找到一些自動化配置為什么沒有生效的具體原因。該報告內容將自動化配置內容分為兩部分:
- positiveMatches中返回的是條件匹配成功的自動化配置
- negativeMatches中返回的是條件匹配不成功的自動化配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
{ "positiveMatches" : { // 條件匹配成功的 "EndpointWebMvcAutoConfiguration" : [ { "condition" : "OnClassCondition" , "message" : "@ConditionalOnClass classes found: javax.servlet.Servlet,org.springframework.web.servlet.DispatcherServlet" }, { "condition" : "OnWebApplicationCondition" , "message" : "found web application StandardServletEnvironment" } ], ... }, "negativeMatches" : { // 條件不匹配成功的 "HealthIndicatorAutoConfiguration.DataSourcesHealthIndicatorConfiguration" : [ { "condition" : "OnClassCondition" , "message" : "required @ConditionalOnClass classes not found: org.springframework.jdbc.core.JdbcTemplate" } ], ... } } |
從如上示例中我們可以看到,每個自動化配置候選項中都有一系列的條件,比如上面沒有成功匹配的HealthIndicatorAutoConfiguration.DataSourcesHealthIndicatorConfiguration
配置,它的先決條件就是需要在工程中包含org.springframework.jdbc.core.JdbcTemplate
類,由于我們沒有引入相關的依賴,它就不會執行自動化配置內容。所以,當我們發現有一些期望的配置沒有生效時,就可以通過該端點來查看沒有生效的具體原因。
- /beans:該端點用來獲取應用上下文中創建的所有Bean。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
[ { "context" : "hello:dev:8881" , "parent" : null , "beans" : [ { "bean" : "org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration$DispatcherServletConfiguration" , "scope" : "singleton" , "type" : "org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration$DispatcherServletConfiguration$$EnhancerBySpringCGLIB$$3440282b" , "resource" : "null" , "dependencies" : [ "serverProperties" , "spring.mvc.CONFIGURATION_PROPERTIES" , "multipartConfigElement" ] }, { "bean" : "dispatcherServlet" , "scope" : "singleton" , "type" : "org.springframework.web.servlet.DispatcherServlet" , "resource" : "class path resource [org/springframework/boot/autoconfigure/web/DispatcherServletAutoConfiguration$DispatcherServletConfiguration.class]" , "dependencies" : [] } ] } ] |
如上示例中,我們可以看到在每個bean中都包含了下面這幾個信息:
- bean:Bean的名稱
- scope:Bean的作用域
- type:Bean的Java類型
- reource:class文件的具體路徑
- dependencies:依賴的Bean名稱
/configprops:該端點用來獲取應用中配置的屬性信息報告。從下面該端點返回示例的片段中,我們看到返回了關于該短信的配置信息,prefix屬性代表了屬性的配置前綴,properties
代表了各個屬性的名稱和值。所以,我們可以通過該報告來看到各個屬性的配置路徑,比如我們要關閉該端點,就可以通過使用endpoints.configprops.enabled=false
來完成設置。
1
2
3
4
5
6
7
8
9
10
11
|
{ "configurationPropertiesReportEndpoint" : { "prefix" : "endpoints.configprops" , "properties" : { "id" : "configprops" , "sensitive" : true , "enabled" : true } }, ... } |
/env:該端點與/configprops
不同,它用來獲取應用所有可用的環境屬性報告。包括:環境變量、JVM屬性、應用的配置配置、命令行中的參數。從下面該端點返回的示例片段中,我們可以看到它不僅返回了應用的配置屬性,還返回了系統屬性、環境變量等豐富的配置信息,其中也包括了應用還沒有沒有使用的配置。所以它可以幫助我們方便地看到當前應用可以加載的配置信息,并配合@ConfigurationProperties
注解將它們引入到我們的應用程序中來進行使用。另外,為了配置屬性的安全,對于一些類似密碼等敏感信息,該端點都會進行隱私保護,但是我們需要讓屬性名中包含:password、secret、key這些關鍵詞,這樣該端點在返回它們的時候會使用*來替代實際的屬性值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
{ "profiles" : [ "dev" ], "server.ports" : { "local.server.port" : 8881 }, "servletContextInitParams" : { }, "systemProperties" : { "idea.version" : "2016.1.3" , "java.runtime.name" : "Java(TM) SE Runtime Environment" , "sun.boot.library.path" : "C:\\Program Files\\Java\\jdk1.8.0_91\\jre\\bin" , "java.vm.version" : "25.91-b15" , "java.vm.vendor" : "Oracle Corporation" , ... }, "systemEnvironment" : { "configsetroot" : "C:\\WINDOWS\\ConfigSetRoot" , "RABBITMQ_BASE" : "E:\\tools\\rabbitmq" , ... }, "applicationConfig: [classpath:/application-dev.properties]" : { "server.port" : "8881" }, "applicationConfig: [classpath:/application.properties]" : { "server.port" : "8885" , "spring.profiles.active" : "dev" , "info.app.name" : "spring-boot-hello" , "info.app.version" : "v1.0.0" , "spring.application.name" : "hello" } } |
/mappings:該端點用來返回所有Spring MVC的控制器映射關系報告。從下面的示例片段中,我們可以看該報告的信息與我們在啟用Spring MVC的Web應用時輸出的日志信息類似,其中bean
屬性標識了該映射關系的請求處理器,method
屬性標識了該映射關系的具體處理類和處理函數。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
{ "/webjars/**" : { "bean" : "resourceHandlerMapping" }, "/**" : { "bean" : "resourceHandlerMapping" }, "/**/favicon.ico" : { "bean" : "faviconHandlerMapping" }, "{[/hello]}" : { "bean" : "requestMappingHandlerMapping" , "method" : "public java.lang.String com.didispace.web.HelloController.index()" }, "{[/mappings || /mappings.json],methods=[GET],produces=[application/json]}" : { "bean" : "endpointHandlerMapping" , "method" : "public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()" }, ... } |
/info:該端點用來返回一些應用自定義的信息。默認情況下,該端點只會返回一個空的json內容。我們可以在application.properties
配置文件中通過info
前綴來設置一些屬性,比如下面這樣:
1
2
|
info.app.name=spring-boot-hello info.app.version=v1. 0.0 |
再訪問/info端點,我們可以得到下面的返回報告,其中就包含了上面我們在應用自定義的兩個參數。
1
2
3
4
5
6
|
{ "app" : { "name" : "spring-boot-hello" , "version" : "v1.0.0" } } |
度量指標類
上面我們所介紹的應用配置類端點所提供的信息報告在應用啟動的時候都已經基本確定了其返回內容,可以說是一個靜態報告。而度量指標類端點提供的報告內容則是動態變化的,這些端點提供了應用程序在運行過程中的一些快照信息,比如:內存使用情況、HTTP請求統計、外部資源指標等。這些端點對于我們構建微服務架構中的監控系統非常有幫助,由于Spring Boot應用自身實現了這些端點,所以我們可以很方便地利用它們來收集我們想要的信息,以制定出各種自動化策略。下面,我們就來分別看看這些強大的端點功能。
/metrics:該端點用來返回當前應用的各類重要度量指標,比如:內存信息、線程信息、垃圾回收信息等。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
{ "mem" : 541305 , "mem.free" : 317864 , "processors" : 8 , "instance.uptime" : 33376471 , "uptime" : 33385352 , "systemload.average" : - 1 , "heap.committed" : 476672 , "heap.init" : 262144 , "heap.used" : 158807 , "heap" : 3701248 , "nonheap.committed" : 65856 , "nonheap.init" : 2496 , "nonheap.used" : 64633 , "nonheap" : 0 , "threads.peak" : 22 , "threads.daemon" : 20 , "threads.totalStarted" : 26 , "threads" : 22 , "classes" : 7669 , "classes.loaded" : 7669 , "classes.unloaded" : 0 , "gc.ps_scavenge.count" : 7 , "gc.ps_scavenge.time" : 118 , "gc.ps_marksweep.count" : 2 , "gc.ps_marksweep.time" : 234 , "httpsessions.max" : - 1 , "httpsessions.active" : 0 , "gauge.response.beans" : 55 , "gauge.response.env" : 10 , "gauge.response.hello" : 5 , "gauge.response.metrics" : 4 , "gauge.response.configprops" : 153 , "gauge.response.star-star" : 5 , "counter.status.200.beans" : 1 , "counter.status.200.metrics" : 3 , "counter.status.200.configprops" : 1 , "counter.status.404.star-star" : 2 , "counter.status.200.hello" : 11 , "counter.status.200.env" : 1 } |
從上面的示例中,我們看到有這些重要的度量值:
- 系統信息:包括處理器數量processors、運行時間uptime和instance.uptime、系統平均負載systemload.average。
- mem.*:內存概要信息,包括分配給應用的總內存數量以及當前空閑的內存數量。這些信息來自java.lang.Runtime。
- heap.*:堆內存使用情況。這些信息來自java.lang.management.MemoryMXBean接口中getHeapMemoryUsage方法獲取的java.lang.management.MemoryUsage。
- nonheap.*:非堆內存使用情況。這些信息來自java.lang.management.MemoryMXBean接口中getNonHeapMemoryUsage方法獲取的java.lang.management.MemoryUsage。
- threads.*:線程使用情況,包括線程數、守護線程數(daemon)、線程峰值(peak)等,這些數據均來自java.lang.management.ThreadMXBean。
- classes.*:應用加載和卸載的類統計。這些數據均來自java.lang.management.ClassLoadingMXBean。
- gc.*:垃圾收集器的詳細信息,包括垃圾回收次數gc.ps_scavenge.count、垃圾回收消耗時間gc.ps_scavenge.time、標記-清除算法的次數gc.ps_marksweep.count、標記-清除算法的消耗時間gc.ps_marksweep.time。這些數據均來自java.lang.management.GarbageCollectorMXBean。
- httpsessions.*:Tomcat容器的會話使用情況。包括最大會話數httpsessions.max和活躍會話數httpsessions.active。該度量指標信息僅在引入了嵌入式Tomcat作為應用容器的時候才會提供。
- gauge.*:HTTP請求的性能指標之一,它主要用來反映一個絕對數值。比如上面示例中的gauge.response.hello: 5,它表示上一次hello請求的延遲時間為5毫秒。
- counter.*:HTTP請求的性能指標之一,它主要作為計數器來使用,記錄了增加量和減少量。如上示例中counter.status.200.hello: 11,它代表了hello請求返回200狀態的次數為11。
對于gauge.*
和counter.*
的統計,這里有一個特殊的內容請求star-star,它代表了對靜態資源的訪問。這兩類度量指標非常有用,我們不僅可以使用它默認的統計指標,還可以在程序中輕松的增加自定義統計值。只需要通過注入org.springframework.boot.actuate.metrics.CounterService和org.springframework.boot.actuate.metrics.GaugeService
來實現自定義的統計指標信息。比如:我們可以像下面這樣自定義實現對hello接口的訪問次數統計。
1
2
3
4
5
6
7
8
9
10
|
@RestController public class HelloController { @Autowired private CounterService counterService; @RequestMapping ( "/hello" ) public String greet() { counterService.increment( "didispace.hello.count" ); return "" ; } } |
/metrics端點可以提供應用運行狀態的完整度量指標報告,這項功能非常的實用,但是對于監控系統中的各項監控功能,它們的監控內容、數據收集頻率都有所不同,如果我們每次都通過全量獲取報告的方式來收集,略顯粗暴。所以,我們還可以通過/metrics/{name}接口來更細粒度的獲取度量信息,比如我們可以通過訪問/metrics/mem.free來獲取當前可用內存數量。
/health:該端點在一開始的示例中我們已經使用過了,它用來獲取應用的各類健康指標信息。在spring-boot-starter-actuator模塊中自帶實現了一些常用資源的健康指標檢測器。這些檢測器都通過HealthIndicator
接口實現,并且會根據依賴關系的引入實現自動化裝配,比如用于檢測磁盤的DiskSpaceHealthIndicator
、檢測DataSource連接是否可用的DataSourceHealthIndicator
等。有時候,我們可能還會用到一些Spring Boot的Starter POMs中還沒有封裝的產品來進行開發,比如:當使用RocketMQ作為消息代理時,由于沒有自動化配置的檢測器,所以我們需要自己來實現一個用來采集健康信息的檢測器。比如,我們可以在Spring Boot的應用中,為org.springframework.boot.actuate.health.HealthIndicator
接口實現一個對RocketMQ的檢測器類:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
@Component public class RocketMQHealthIndicator implements HealthIndicator { @Override public Health health() { int errorCode = check(); if (errorCode != 0 ) { return Health.down().withDetail( "Error Code" , errorCode).build(); } return Health.up().build(); } private int check() { // 對監控對象的檢測操作 } } |
通過重寫health()函數來實現健康檢查,返回的Heath對象中,共有兩項內容,一個是狀態信息,除了該示例中的UP與DOWN之外,還有UNKNOWN和OUT_OF_SERVICE,可以根據需要來實現返回;還有一個詳細信息,采用Map的方式存儲,在這里通過withDetail函數,注入了一個Error Code信息,我們也可以填入一下其他信息,比如,檢測對象的IP地址、端口等。重新啟動應用,并訪問/health接口,我們在返回的JSON字符串中,將會包含了如下信息:
1
2
3
|
"rocketMQ" : { "status" : "UP" } |
/dump:該端點用來暴露程序運行中的線程信息。它使用java.lang.management.ThreadMXBean的dumpAllThreads
方法來返回所有含有同步信息的活動線程詳情。
/trace:該端點用來返回基本的HTTP跟蹤信息。默認情況下,跟蹤信息的存儲采用org.springframework.boot.actuate.trace.InMemoryTraceRepository
實現的內存方式,始終保留最近的100條請求記錄。它記錄的內容格式如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
[ { "timestamp" : 1482570022463 , "info" : { "method" : "GET" , "path" : "/metrics/mem" , "headers" : { "request" : { "host" : "localhost:8881" , "connection" : "keep-alive" , "cache-control" : "no-cache" , "user-agent" : "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36" , "postman-token" : "9817ea4d-ad9d-b2fc-7685-9dff1a1bc193" , "accept" : "*/*" , "accept-encoding" : "gzip, deflate, sdch" , "accept-language" : "zh-CN,zh;q=0.8" }, "response" : { "X-Application-Context" : "hello:dev:8881" , "Content-Type" : "application/json;charset=UTF-8" , "Transfer-Encoding" : "chunked" , "Date" : "Sat, 24 Dec 2016 09:00:22 GMT" , "status" : "200" } } } }, ... ] |
操作控制類
仔細的讀者可能會發現,我們在“初識Actuator”時運行示例的控制臺中輸出的所有監控端點,已經在介紹應用配置類端點和度量指標類端點時都講解完了。那么還有哪些是操作控制類端點呢?實際上,由于之前介紹的所有端點都是用來反映應用自身的屬性或是運行中的狀態,相對于操作控制類端點沒有那么敏感,所以他們默認都是啟用的。而操作控制類端點擁有更強大的控制能力,如果要使用它們的話,需要通過屬性來配置開啟。
在原生端點中,只提供了一個用來關閉應用的端點:/shutdown。我們可以通過如下配置開啟它:
1
|
endpoints.shutdown.enabled= true |
在配置了上述屬性之后,只需要訪問該應用的/shutdown端點就能實現關閉該應用的遠程操作。由于開放關閉應用的操作本身是一件非常危險的事,所以真正在線上使用的時候,我們需要對其加入一定的保護機制,比如:定制Actuator的端點路徑、整合Spring Security進行安全校驗等。
以上所述是小編給大家介紹的Spring Boot Actuator監控端點小結,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網站的支持!
原文鏈接:http://blog.didispace.com/spring-boot-actuator-1/