微服務的特點決定了功能模塊的部署是分布式的,大部分功能模塊都是運行在不同的機器上,彼此通過服務調(diào)用進行交互,前后臺的業(yè)務流會經(jīng)過很多個微服務的處理和傳遞,出現(xiàn)了異常如何快速定位是哪個環(huán)節(jié)出現(xiàn)了問題?
在這種框架下,微服務的監(jiān)控顯得尤為重要。本文主要結合Spring Boot Actuator,跟大家一起分享微服務Spring Boot Actuator的常見用法,方便我們在日常中對我們的微服務進行監(jiān)控治理。
Actuator監(jiān)控
Spring Boot使用“習慣優(yōu)于配置的理念”,采用包掃描和自動化配置的機制來加載依賴jar中的Spring bean,不需要任何Xml配置,就可以實現(xiàn)Spring的所有配置。雖然這樣做能讓我們的代碼變得非常簡潔,但是整個應用的實例創(chuàng)建和依賴關系等信息都被離散到了各個配置類的注解上,這使得我們分析整個應用中資源和實例的各種關系變得非常的困難。
Actuator是Spring Boot提供的對應用系統(tǒng)的自省和監(jiān)控的集成功能,可以查看應用配置的詳細信息,例如自動化配置信息、創(chuàng)建的Spring beans以及一些環(huán)境屬性等。
Actuator監(jiān)控只需要添加以下依賴就可以完成
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
< 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 > < dependency > < groupId >org.springframework.boot</ groupId > < artifactId >spring-boot-starter-security</ artifactId > </ dependency > </ dependencies > |
為了保證actuator暴露的監(jiān)控接口的安全性,需要添加安全控制的依賴spring-boot-start-security依賴,訪問應用監(jiān)控端點時,都需要輸入驗證信息。Security依賴,可以選擇不加,不進行安全管理,但不建議這么做。
Actuator 的 REST 接口
Actuator監(jiān)控分成兩類:原生端點和用戶自定義端點;自定義端點主要是指擴展性,用戶可以根據(jù)自己的實際應用,定義一些比較關心的指標,在運行期進行監(jiān)控。
原生端點是在應用程序里提供眾多 Web 接口,通過它們了解應用程序運行時的內(nèi)部狀況。原生端點又可以分成三類:
- 應用配置類:可以查看應用在運行期的靜態(tài)信息:例如自動配置信息、加載的springbean信息、yml文件配置信息、環(huán)境信息、請求映射信息;
- 度量指標類:主要是運行期的動態(tài)信息,例如堆棧、請求連、一些健康指標、metrics信息等;
- 操作控制類:主要是指shutdown,用戶可以發(fā)送一個請求將應用的監(jiān)控功能關閉。
Actuator 提供了 13 個接口,具體如下表所示。
HTTP 方法 | 路徑 | 描述 |
---|---|---|
GET | /autoconfig | 提供了一份自動配置報告,記錄哪些自動配置條件通過了,哪些沒通過 |
GET | /configprops | 描述配置屬性(包含默認值)如何注入Bean |
GET | /beans | 描述應用程序上下文里全部的Bean,以及它們的關系 |
GET | /dump | 獲取線程活動的快照 |
GET | /env | 獲取全部環(huán)境屬性 |
GET | /env/{name} | 根據(jù)名稱獲取特定的環(huán)境屬性值 |
GET | /health | 報告應用程序的健康指標,這些值由HealthIndicator的實現(xiàn)類提供 |
GET | /info | 獲取應用程序的定制信息,這些信息由info打頭的屬性提供 |
GET | /mappings | 描述全部的URI路徑,以及它們和控制器(包含Actuator端點)的映射關系 |
GET | /metrics | 報告各種應用程序度量信息,比如內(nèi)存用量和HTTP請求計數(shù) |
GET | /metrics/{name} | 報告指定名稱的應用程序度量值 |
POST | /shutdown | 關閉應用程序,要求endpoints.shutdown.enabled設置為true |
GET | /trace | 提供基本的HTTP請求跟蹤信息(時間戳、HTTP頭等) |
快速上手
相關配置
項目依賴
1
2
3
4
5
6
7
8
9
10
|
< 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 > |
配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
server: port: 8080 management: security: enabled: false #關掉安全認證 port: 8088 #管理端口調(diào)整成8088 context-path: /monitor #actuator的訪問路徑 endpoints: shutdown: enabled: true info: app: name: spring-boot-actuator version: 1.0.0 |
- management.security.enabled=false 默認有一部分信息需要安全驗證之后才可以查看,如果去掉這些安全認證,直接設置management.security.enabled=false
- management.context-path=/monitor 代表啟用單獨的url地址來監(jiān)控Spring Boot應用,為了安全一般都啟用獨立的端口來訪問后端的監(jiān)控信息
- endpoints.shutdown.enabled=true 啟用接口關閉Spring Boot
配置完成之后,啟動項目就可以繼續(xù)驗證各個監(jiān)控功能了。
命令詳解
autoconfig
Spring Boot的自動配置功能非常便利,但有時候也意味著出問題比較難找出具體的原因。使用 autoconfig 可以在應用運行時查看代碼了某個配置在什么條件下生效,或者某個自動配置為什么沒有生效。
啟動示例項目,訪問: http://localhost:8088/monitor/autoconfig 返回部分信息如下:
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
|
{ "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" } ] } } } |
configprops
查看配置文件中設置的屬性內(nèi)容,以及一些配置屬性的默認值。
啟動示例項目,訪問: http://localhost:8088/monitor/configprops 返回部分信息如下:
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
|
{ ... "environmentEndpoint" : { "prefix" : "endpoints.env" , "properties" : { "id" : "env" , "sensitive" : true , "enabled" : true } }, "spring.http.multipart-org.springframework.boot.autoconfigure.web.MultipartProperties" : { "prefix" : "spring.http.multipart" , "properties" : { "maxRequestSize" : "10MB" , "fileSizeThreshold" : "0" , "location" : null , "maxFileSize" : "1MB" , "enabled" : true , "resolveLazily" : false } }, "infoEndpoint" : { "prefix" : "endpoints.info" , "properties" : { "id" : "info" , "sensitive" : false , "enabled" : true } } ... } |
beans
根據(jù)示例就可以看出,展示了bean的別名、類型、是否單例、類的地址、依賴等信息。
啟動示例項目,訪問: http://localhost:8088/monitor/beans 返回部分信息如下:
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
|
[ { "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" : [ ] } } ] |
dump
/dump 接口會生成當前線程活動的快照。這個功能非常好,方便我們在日常定位問題的時候查看線程的情況。 主要展示了線程名、線程ID、線程的狀態(tài)、是否等待鎖資源等信息。
啟動示例項目,訪問: http://localhost:8088/monitor/dump 返回部分信息如下:
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
|
[ { "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" : "park" , "fileName" : "LockSupport.java" , "lineNumber" : 175, "className" : "java.util.concurrent.locks.LockSupport" , "nativeMethod" : false }, { "methodName" : "await" , "fileName" : "AbstractQueuedSynchronizer.java" , "lineNumber" : 2039, "className" : "java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject" , "nativeMethod" : false }, ... { "methodName" : "getTask" , "fileName" : "ThreadPoolExecutor.java" , "lineNumber" : 1067, "className" : "java.util.concurrent.ThreadPoolExecutor" , "nativeMethod" : false }, { "methodName" : "runWorker" , "fileName" : "ThreadPoolExecutor.java" , "lineNumber" : 1127, "className" : "java.util.concurrent.ThreadPoolExecutor" , "nativeMethod" : false }, { "methodName" : "run" , "fileName" : "ThreadPoolExecutor.java" , "lineNumber" : 617, "className" : "java.util.concurrent.ThreadPoolExecutor$Worker" , "nativeMethod" : false }, { "methodName" : "run" , "fileName" : "TaskThread.java" , "lineNumber" : 61, "className" : "org.apache.tomcat.util.threads.TaskThread$WrappingRunnable" , "nativeMethod" : false }, { "methodName" : "run" , "fileName" : "Thread.java" , "lineNumber" : 745, "className" : "java.lang.Thread" , "nativeMethod" : false } ], "lockedMonitors" : [ ], "lockedSynchronizers" : [ ], "lockInfo" : { "className" : "java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject" , "identityHashCode" : 372286721 } } ... ] |
env
展示了系統(tǒng)環(huán)境變量的配置信息,包括使用的環(huán)境變量、JVM 屬性、命令行參數(shù)、項目使用的jar包等信息。和configprops不同的是,configprops關注于配置信息,env關注運行環(huán)境信息。
啟動示例項目,訪問: http://localhost:8088/monitor/env 返回部分信息如下:
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
|
{ "profiles" : [ ], "server.ports" : { "local.management.port" : 8088, "local.server.port" : 8080 }, "servletContextInitParams" : { }, "systemProperties" : { "com.sun.management.jmxremote.authenticate" : "false" , "java.runtime.name" : "Java(TM) SE Runtime Environment" , "spring.output.ansi.enabled" : "always" , "sun.boot.library.path" : "C:\\Program Files\\Java\\jdk1.8.0_101\\jre\\bin" , "java.vm.version" : "25.101-b13" , "java.vm.vendor" : "Oracle Corporation" , "java.vendor.url" : "http://java.oracle.com/" , "java.rmi.server.randomIDs" : "true" , "path.separator" : ";" , "java.vm.name" : "Java HotSpot(TM) 64-Bit Server VM" , "file.encoding.pkg" : "sun.io" , "user.country" : "CN" , "user.script" : "" , "sun.java.launcher" : "SUN_STANDARD" , "sun.os.patch.level" : "" , "PID" : "5268" , "com.sun.management.jmxremote.port" : "60093" , "java.vm.specification.name" : "Java Virtual Machine Spe |
為了避免敏感信息暴露到 /env 里,所有名為password、secret、key(或者名字中最后一段是這些)的屬性在 /env 里都會加上“*”。舉個例子,如果有一個屬性名字是database.password,那么它在/env中的顯示效果是這樣的:
"database.password":"******"
/env/{name}用法
就是env的擴展 可以獲取指定配置信息,比如: http://localhost:8088/monitor/env/java.vm.version ,返回: {"java.vm.version":"25.101-b13"}
health
可以看到 HealthEndPoint 給我們提供默認的監(jiān)控結果,包含 磁盤檢測和數(shù)據(jù)庫檢測
啟動示例項目,訪問: http://localhost:8088/monitor/health 返回部分信息,下面的JSON響應是由狀態(tài)、磁盤空間和db。描述了應用程序的整體健康狀態(tài),UP 表明應用程序是健康的。磁盤空間描述總磁盤空間,剩余的磁盤空間和最小閾值。 application.properties 閾值是可配置的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
{ "status" : "UP" , "diskSpace" : { "status" : "UP" , "total" : 209715195904, "free" : 183253909504, "threshold" : 10485760 } "db" : { "status" : "UP" , "database" : "MySQL" , "hello" : 1 } } |
其實看 Spring Boot-actuator 源碼,你會發(fā)現(xiàn) HealthEndPoint 提供的信息不僅限于此,org.springframework.boot.actuate.health 包下 你會發(fā)現(xiàn) ElasticsearchHealthIndicator、RedisHealthIndicator、RabbitHealthIndicator 等
info
info就是我們自己配置在配置文件中以Info開頭的配置信息,比如我們在示例項目中的配置是:
1
2
3
4
|
info: app: name: spring-boot-actuator version: 1.0.0 |
啟動示例項目,訪問: http://localhost:8088/monitor/info 返回部分信息如下:
1
2
3
4
5
6
|
{ "app" : { "name" : "spring-boot-actuator" , "version" : "1.0.0" } } |
mappings
描述全部的URI路徑,以及它們和控制器的映射關系
啟動示例項目,訪問: http://localhost:8088/monitor/mappings 返回部分信息如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
{ "/**/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)" } } |
metrics
最重要的監(jiān)控內(nèi)容之一,主要監(jiān)控了JVM內(nèi)容使用、GC情況、類加載信息等。
啟動示例項目,訪問: http://localhost:8088/monitor/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
|
{ "mem" : 337132, "mem.free" : 183380, "processors" : 4, "instance.uptime" : 254552, "uptime" : 259702, "systemload.average" : -1.0, "heap.committed" : 292864, "heap.init" : 129024, "heap.used" : 109483, "heap" : 1827840, "nonheap.committed" : 45248, "nonheap.init" : 2496, "nonheap.used" : 44269, "nonheap" : 0, "threads.peak" : 63, "threads.daemon" : 43, "threads.totalStarted" : 83, "threads" : 46, "classes" : 6357, "classes.loaded" : 6357, "classes.unloaded" : 0, "gc.ps_scavenge.count" : 8, "gc.ps_scavenge.time" : 99, "gc.ps_marksweep.count" : 1, "gc.ps_marksweep.time" : 43, "httpsessions.max" : -1, "httpsessions.active" : 0 } |
對 /metrics 接口提供的信息進行簡單分類如下表:
分類 | 前綴 | 報告內(nèi)容 |
---|---|---|
垃圾收集器 | gc.* | 已經(jīng)發(fā)生過的垃圾收集次數(shù),以及垃圾收集所耗費的時間,適用于標記-清理垃圾收集器和并行垃圾收集器(數(shù)據(jù)源自java.lang.management. GarbageCollectorMXBean) |
內(nèi)存 | mem.* | 分配給應用程序的內(nèi)存數(shù)量和空閑的內(nèi)存數(shù)量(數(shù)據(jù)源自java.lang. Runtime) |
堆 | heap.* | 當前內(nèi)存用量(數(shù)據(jù)源自java.lang.management.MemoryUsage) |
類加載器 | classes.* | JVM類加載器加載與卸載的類的數(shù)量(數(shù)據(jù)源自java.lang. management.ClassLoadingMXBean) |
系統(tǒng) | processors、instance.uptime、uptime、systemload.average | 系統(tǒng)信息,例如處理器數(shù)量(數(shù)據(jù)源自java.lang.Runtime)、運行時間(數(shù)據(jù)源自java.lang.management.RuntimeMXBean)、平均負載(數(shù)據(jù)源自java.lang.management.OperatingSystemMXBean) |
線程池 | thread.* | 線程、守護線程的數(shù)量,以及JVM啟動后的線程數(shù)量峰值(數(shù)據(jù)源自 java.lang .management.ThreadMXBean) |
數(shù)據(jù)源 | datasource.* | 數(shù)據(jù)源連接的數(shù)量(源自數(shù)據(jù)源的元數(shù)據(jù),僅當Spring應用程序上下文里存在 DataSource Bean 的時候才會有這個信息) |
Tomcat 會話 | httpsessions.* | Tomcat的活躍會話數(shù)和最大會話數(shù)(數(shù)據(jù)源自嵌入式Tomcat的Bean,僅在使用嵌入式Tomcat服務器運行應用程序時才有這個信息) |
HTTP | counter.status. 、gauge.response. | 多種應用程序服務HTTP請求的度量值與計數(shù)器 |
解釋說明:
- 請注意,這里的一些度量值,比如數(shù)據(jù)源和Tomcat會話,僅在應用程序中運行特定組件時才有數(shù)據(jù)。你還可以注冊自己的度量信息。
- HTTP的計數(shù)器和度量值需要做一點說明。counter.status 后的值是HTTP狀態(tài)碼,隨后是所請求的路徑。舉個例子,counter.status.200.metrics 表明/metrics端點返回 200(OK) 狀態(tài)碼的次數(shù)。
- HTTP的度量信息在結構上也差不多,卻在報告另一類信息。它們?nèi)恳詆auge.response 開頭,,表明這是HTTP響應的度量信息。前綴后是對應的路徑。度量值是以毫秒為單位的時間,反映了最近處理該路徑請求的耗時。
- 這里還有幾個特殊的值需要注意。root路徑指向的是根路徑或/。star-star代表了那些Spring 認為是靜態(tài)資源的路徑,包括圖片、JavaScript和樣式表,其中還包含了那些找不到的資源。這就是為什么你經(jīng)常會看到 counter.status.404.star-star,這是返回了HTTP 404 (NOT FOUND) 狀態(tài)的請求數(shù)。
- /metrics 接口會返回所有的可用度量值,但你也可能只對某個值感興趣。要獲取單個值,請求時可以在URL后加上對應的鍵名。例如,要查看空閑內(nèi)存大小,可以向 /metrics/mem.free 發(fā)一 個GET請求。例如訪問: http://localhost:8088/monitor/metrics/mem.free ,返回: {"mem.free":178123} 。
shutdown
開啟接口優(yōu)雅關閉Spring Boot應用,要使用這個功能首先需要在配置文件中開啟:
1
2
3
|
endpoints: shutdown: enabled: true |
配置完成之后,啟動示例項目,訪問: http://localhost:8088/monitor/shutdown 返回部分信息如下:
1
2
3
|
{ "message" : "Shutting down, bye..." } |
此時你會發(fā)現(xiàn)應用已經(jīng)被關閉。
trace
/trace 接口能報告所有Web請求的詳細信息,包括請求方法、路徑、時間戳以及請求和響應的頭信息,記錄每一次請求的詳細信息。
啟動示例項目,先訪問一次: http://localhost:8080/hello ,再到瀏覽器執(zhí)行: http://localhost:8088/monitor/trace 查看返回信息:
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
|
[ { "timestamp" : 1516780334777, "info" : { "method" : "GET" , "path" : "/hello" , "headers" : { "request" : { "host" : "localhost:8080" , "connection" : "keep-alive" , "cache-control" : "max-age=0" , "user-agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36" , "upgrade-insecure-requests" : "1" , "accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8" , "accept-encoding" : "gzip, deflate, br" , "accept-language" : "zh-CN,zh;q=0.9" , "cookie" : "UM_distinctid=16053ba344f1cd-0dc220c44cc94-b7a103e-13c680-16053ba3450751; Hm_lvt_0fb30c642c5f6453f17d881f529a1141=1513076406,1514961720,1515649377; CNZZDATA1260945749=232252692-1513233181-%7C1516085149; Hm_lvt_6d8e8bb59814010152d98507a18ad229=1515247964,1515296008,1515672972,1516086283" }, "response" : { "X-Application-Context" : "application:8080" , "Content-Type" : "text/html;charset=UTF-8" , "Content-Length" : "11" , "Date" : "Wed, 24 Jan 2018 07:52:14 GMT" , "status" : "200" } }, "timeTaken" : "4" } } ] |
上述信息展示了,/hello請求的詳細信息。
其它配置
敏感信息訪問限制
根據(jù)上面表格,鑒權為false的,表示不敏感,可以隨意訪問,否則就是做了一些保護,不能隨意訪問。
1
|
endpoints.mappings.sensitive=false |
這樣需要對每一個都設置,比較麻煩。敏感方法默認是需要用戶擁有ACTUATOR角色,因此,也可以設置關閉安全限制:
1
|
management.security.enabled=false |
或者配合Spring Security做細粒度控制。
啟用和禁用接口
雖然Actuator的接口都很有用,但你不一定需要全部這些接口。默認情況下,所有接口(除 了/shutdown)都啟用。比如要禁用 /metrics 接口,則可以設置如下:
1
|
endpoints.metrics.enabled = false |
如果你只想打開一兩個接口,那就先禁用全部接口,然后啟用那幾個你要的,這樣更方便。
1
2
|
endpoints.enabled = false endpoints.metrics.enabled = true |
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:http://www.ityouknow.com/springboot/2018/02/06/spring-boot-actuator.html