1 Spring Boot監(jiān)控機(jī)制
在 Spring 2.x 之前,SpringBoot 使用 Actuator 模塊進(jìn)行監(jiān)控,而在 Spring 2.x 之后,SpringBoot 使用了 Micrometer 進(jìn)行監(jiān)控。
Spring Boot Actuator 模塊提供了生產(chǎn)級(jí)別的功能,比如健康檢查,審計(jì),指標(biāo)收集,HTTP 跟蹤等,幫助我們監(jiān)控和管理 Spring Boot 應(yīng)用。這個(gè)模塊是一個(gè)采集應(yīng)用內(nèi)部信息暴露給外部的模塊,上述的功能都可以通過(guò) HTTP 和 JMX 訪問(wèn)。
在 Spring 2.x 之后,Actuator 使用 Micrometer 與這些外部應(yīng)用程序監(jiān)視系統(tǒng)集成。這樣一來(lái),只需很少的配置即可輕松集成外部的監(jiān)控系統(tǒng)。
那什么是 Micrometer 呢?
Micrometer 為 Java 平臺(tái)上的性能數(shù)據(jù)收集提供了一個(gè)通用的 API,應(yīng)用程序只需要使用 Micrometer 的通用 API 來(lái)收集性能指標(biāo)即可。Micrometer 會(huì)負(fù)責(zé)完成與不同監(jiān)控系統(tǒng)的適配工作。這就使得切換監(jiān)控系統(tǒng)變得很容易。
簡(jiǎn)單地說(shuō),actuator 是真正去采集數(shù)據(jù)的模塊,而 Micrometer 更像是一個(gè)適配器,將 actuator 采集到的數(shù)據(jù)適配給各種監(jiān)控工具。
2 Spring Boot Actuator
作為SpringBoot的四大核心之一,Actuator讓你時(shí)刻探知SpringBoot服務(wù)運(yùn)行狀態(tài)信息,是保障系統(tǒng)正常運(yùn)行必不可少的組件。
??spring-boot-starter-actuator提供的是一系列HTTP或者JMX監(jiān)控端點(diǎn),通過(guò)監(jiān)控端點(diǎn)我們可以獲取到系統(tǒng)的運(yùn)行統(tǒng)計(jì)信息,同時(shí),我們可以自己選擇開(kāi)啟需要的監(jiān)控端點(diǎn),也可以自定義擴(kuò)展監(jiān)控端點(diǎn)。
??Actuator通過(guò)端點(diǎn)對(duì)外暴露的監(jiān)控信息是JSON格式數(shù)據(jù),我們需要使用界面來(lái)展示,目前使用比較多的就是Spring Boot Admin或者Prometheus + Grafana的方式;
- Spring Boot Admin實(shí)現(xiàn)起來(lái)相對(duì)比較簡(jiǎn)單,不存在數(shù)據(jù)庫(kù),不能存儲(chǔ)和展示歷史監(jiān)控?cái)?shù)據(jù);
-
Prometheus(時(shí)序數(shù)據(jù)庫(kù)) + Grafana(界面)的方式相比較而言功能更豐富,提供歷史記錄存儲(chǔ),界面展示也比較美觀。
??相比較而言,Prometheus + Grafana的方式更為流行一些,現(xiàn)在的微服務(wù)及Kubernetes基本是采用這種方式的。但是對(duì)于小的項(xiàng)目或者單體應(yīng)用,Spring Boot Admin會(huì)更加方便快捷一些。
2.1 Actuator endpoints
Spring Boot 提供了所謂的 endpoints (下文翻譯為端點(diǎn))給外部來(lái)與應(yīng)用程序進(jìn)行訪問(wèn)和交互。
打比方來(lái)說(shuō),/health 端點(diǎn) 提供了關(guān)于應(yīng)用健康情況的一些基礎(chǔ)信息。metrics 端點(diǎn)提供了一些有用的應(yīng)用程序指標(biāo)(JVM 內(nèi)存使用、系統(tǒng)CPU使用等)。
這些 Actuator 模塊本來(lái)就有的端點(diǎn)我們稱(chēng)之為原生端點(diǎn)。根據(jù)端點(diǎn)的作用的話,我們大概可以分為三大類(lèi):
應(yīng)用配置類(lèi):獲取應(yīng)用程序中加載的應(yīng)用配置、環(huán)境變量、自動(dòng)化配置報(bào)告等與Spring Boot應(yīng)用密切相關(guān)的配置類(lèi)信息。
度量指標(biāo)類(lèi):獲取應(yīng)用程序運(yùn)行過(guò)程中用于監(jiān)控的度量指標(biāo),比如:內(nèi)存信息、線程池信息、HTTP請(qǐng)求統(tǒng)計(jì)等。
操作控制類(lèi):提供了對(duì)應(yīng)用的關(guān)閉等操作類(lèi)功能。
Actuator 提供的所有 endpoint:
此處使用的是SpringBoot 2.2.8

下面介紹幾個(gè)核心的端點(diǎn)
2.2 /health 端點(diǎn)
當(dāng)我們開(kāi)啟health的健康端點(diǎn)時(shí),我們能夠查到應(yīng)用健康信息是一個(gè)匯總的信息,健康信息包含磁盤(pán)空間、redis、DB,如果啟用監(jiān)控的這個(gè)spring boot應(yīng)用確實(shí)是連接了redis和mysql DB,那actuator就自動(dòng)給監(jiān)控起來(lái)了,很方便、很有用。
-
/health原理
Spring boot的健康信息都是從ApplicationContext中的各種HealthIndicator Beans中收集到的,Spring boot框架中包含了大量的HealthIndicators的實(shí)現(xiàn)類(lèi),當(dāng)然你也可以實(shí)現(xiàn)自己認(rèn)為的健康狀態(tài)。默認(rèn)情況下,最終的spring boot應(yīng)用的狀態(tài)是由HealthAggregator匯總而成的,匯總的算法是:
- 設(shè)置狀態(tài)碼順序:setStatusOrder(Status.DOWN, Status.OUT_OF_SERVICE, Status.UP, Status.UNKNOWN)。
- 過(guò)濾掉不能識(shí)別的狀態(tài)碼。
- 如果無(wú)任何狀態(tài)碼,整個(gè)spring boot應(yīng)用的狀態(tài)是 UNKNOWN。
- 將所有收集到的狀態(tài)碼按照 1 中的順序排序。
- 返回有序狀態(tài)碼序列中的第一個(gè)狀態(tài)碼,作為整個(gè)spring boot應(yīng)用的狀態(tài)。
//配置 always:對(duì)所有用戶(hù)暴露詳細(xì)信息
management.endpoint.health.show-details=always
{
"status": "UP",
"details": {
"diskSpace": {
"status": "UP",
"details": {
"total": 250685575168,
"free": 172252426240,
"threshold": 10485760
}
},
"redis": {
"status": "UP",
"details": {
"version": "3.2.11"
}
},
"db": {
"status": "UP",
"details": {
"database": "Mysql",
"hello": "Hello"
}
}
}
}
- 自定義 HealthIndicator
有時(shí)候需要提供自定義的健康狀態(tài)檢查信息,你可以通過(guò)實(shí)現(xiàn)HealthIndicator的接口來(lái)實(shí)現(xiàn),并將該實(shí)現(xiàn)類(lèi)注冊(cè)為spring bean。
你需要實(shí)現(xiàn)其中的health()方法,并返回自定義的健康狀態(tài)響應(yīng)信息,該響應(yīng)信息應(yīng)該包括一個(gè)狀態(tài)碼和要展示詳細(xì)信息。demo 如下
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;
@Component
public class MyHealthIndicator implements HealthIndicator {
@Override
public Health health() {
int errorCode = check(); // perform some specific health check
if (errorCode != 0) {
return Health.down().withDetail("Error Code", errorCode).build();
}
return Health.up().build();
}
}
2.3 /metrics 端點(diǎn)
/metrics端點(diǎn)用來(lái)返回當(dāng)前應(yīng)用的各類(lèi)重要度量指標(biāo),比如:內(nèi)存信息、線程信息、垃圾回收信息、tomcat、數(shù)據(jù)庫(kù)連接池等。


除了使用 metrics 端點(diǎn)默認(rèn)的這些統(tǒng)計(jì)指標(biāo)外,我們還可以實(shí)現(xiàn)自定義統(tǒng)計(jì)指標(biāo)。具體實(shí)現(xiàn)以后有機(jī)會(huì)再詳細(xì)描述
2.4 /heapdump 端點(diǎn)
訪問(wèn): http://localhost:8080/actuator/heapdump 會(huì)自動(dòng)生成一個(gè) Jvm 的堆文件 heapdump。我們可以使用 JDK 自帶的 Jvm 監(jiān)控工具 VisualVM 打開(kāi)此文件查看內(nèi)存快照。
2.5 /threaddump 端點(diǎn)
查看線程的情況。 主要展示了線程名、線程ID、線程的狀態(tài)、是否等待鎖資源、線程堆棧等信息。就是可能查看起來(lái)不太直觀。
2.6 自定義Endpoint
默認(rèn)的端點(diǎn)雖然可以滿(mǎn)足大多數(shù)的需求,但一些特殊的需求還是需要能夠支持自定義端點(diǎn)的。
自定義 Endpoint 端點(diǎn),只需要在我們的新建Bean上使用 @Endpoint 注解即可, Bean 中的方法就可以通過(guò) JMX 或者 HTTP 公開(kāi)。
// id屬性代表新增的端點(diǎn)名稱(chēng)
// 利用@ReadOperation @WritOperation注解,在端點(diǎn)中添加信息
@Component
@Endpoint(id = "myservice")
public class MyServiceEndPoint {
@ReadOperation
public Map getDockerInfo () {
//端點(diǎn)的讀操作
return Collections.singletonMap("dockerInfo", "docker start...");
}
@WriteOperation
private void restartDocker(){
System.out.println("docker restarted....");
}
}

2.8 導(dǎo)入依賴(lài)
<!-- spring boot 健康監(jiān)控 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
3 Promethues + Grafana
3.1 Prometheus介紹
Prometheus: 是一款開(kāi)源的系統(tǒng)和服務(wù)監(jiān)控系統(tǒng),屬于云原生計(jì)算基金會(huì)項(xiàng)目。它可以通過(guò)設(shè)置的時(shí)間間隔從配置的目標(biāo)系統(tǒng)采集指標(biāo)數(shù)據(jù),保存指標(biāo)數(shù)據(jù)(時(shí)序數(shù)據(jù)庫(kù)),評(píng)估規(guī)則表達(dá)式,顯示結(jié)果,并在檢測(cè)到指定條件時(shí)觸發(fā)警報(bào)。
- 多維數(shù)據(jù)模型:Prometheus 實(shí)現(xiàn)了一個(gè)高維數(shù)據(jù)模型,它從根本上將所有數(shù)據(jù)存儲(chǔ)為時(shí)間序列:屬于同一指標(biāo)和同一組標(biāo)記維度的時(shí)間戳值。 除了存儲(chǔ)的時(shí)間序列,Prometheus 可能會(huì)生成臨時(shí)派生的時(shí)間序列作為查詢(xún)的結(jié)果。
- 高效存儲(chǔ):Prometheus 以高效的自定義格式將時(shí)間序列存儲(chǔ)在內(nèi)存和本地磁盤(pán)上(內(nèi)置TSDB數(shù)據(jù)庫(kù),同時(shí)也提供了遠(yuǎn)程存儲(chǔ)接口),擴(kuò)展是通過(guò)功能分片和聯(lián)合來(lái)實(shí)現(xiàn)的。
- PromQL:一種強(qiáng)大且靈活的查詢(xún)語(yǔ)言,PromQL 允許對(duì)收集的時(shí)間序列數(shù)據(jù)進(jìn)行切片和切塊,以生成臨時(shí)圖形、表格和警報(bào)。
- 不依賴(lài)分布式存儲(chǔ),操作簡(jiǎn)單:每臺(tái)服務(wù)器的可靠性都是獨(dú)立的,僅依賴(lài)于本地存儲(chǔ)。用 Go 編寫(xiě),所有二進(jìn)制文件都是靜態(tài)鏈接的,易于部署。
- HTTP拉取模型: 通過(guò)抓取HTTP端點(diǎn)采集時(shí)序數(shù)據(jù)。
- 通過(guò)用于批處理作業(yè)的中間網(wǎng)關(guān)支持推送時(shí)間序列數(shù)據(jù)。
- 通過(guò)服務(wù)發(fā)現(xiàn)或靜態(tài)配置發(fā)現(xiàn)目標(biāo)。
- 出色的可視化:Prometheus 有多種數(shù)據(jù)可視化模式,內(nèi)置表達(dá)式瀏覽器、Grafana 集成和控制臺(tái)模板語(yǔ)言。
- 支持分層和水平聯(lián)合。
3.2 Grafana介紹
雖然Prometheus也支持可視化界面展示,但是界面不美觀,更多人選擇使用Grafana來(lái)展示Prometheus的監(jiān)控?cái)?shù)據(jù)。
Grafana:Grafana是一款開(kāi)源的數(shù)據(jù)可視化工具。它提供對(duì)數(shù)據(jù)指標(biāo)的查詢(xún)、可視化和告警,它可以實(shí)現(xiàn)無(wú)論數(shù)據(jù)存儲(chǔ)在哪里,都可以與您的團(tuán)隊(duì)創(chuàng)建、探索和共享十分美觀的儀表盤(pán)數(shù)據(jù)可視化,并培養(yǎng)數(shù)據(jù)驅(qū)動(dòng)的文化。
- 可視化:具有多種選項(xiàng)的快速靈活的客戶(hù)端圖表。面板插件提供了許多不同的方式來(lái)可視化指標(biāo)和日志。
- 動(dòng)態(tài)儀表板:使用在儀表板頂部顯示為下拉列表的模板變量創(chuàng)建動(dòng)態(tài)和可重復(fù)使用的儀表板。
- 探索指標(biāo):通過(guò)即席查詢(xún)(是用戶(hù)根據(jù)自己的需求,靈活的選擇查詢(xún)條件,系統(tǒng)能夠根據(jù)用戶(hù)的選擇生成相應(yīng)的統(tǒng)計(jì)報(bào)表)和動(dòng)態(tài)鉆取探索您的數(shù)據(jù)。拆分視圖并并排比較不同的時(shí)間范圍、查詢(xún)和數(shù)據(jù)源。
- 探索日志:體驗(yàn)從指標(biāo)切換到帶有保留標(biāo)簽過(guò)濾器的日志的魔力。快速搜索所有日志或?qū)崟r(shí)流式傳輸它們。
- 告警:為您最重要的指標(biāo)直觀地定義告警規(guī)則。Grafana 將持續(xù)評(píng)估并向 Slack、PagerDuty、VictorOps、OpsGenie 等系統(tǒng)發(fā)送通知。
- 混合數(shù)據(jù)源:在同一個(gè)圖中混合不同的數(shù)據(jù)源!您可以基于每個(gè)查詢(xún)指定數(shù)據(jù)源。這甚至適用于自定義數(shù)據(jù)源。
3.3 Prometheus+Grafana
我們使用Docker來(lái)安裝需要的Prometheus+Grafana,通常情況下,我們會(huì)根據(jù)業(yè)務(wù)需求來(lái)安裝需要的組件,在這里健康監(jiān)控系統(tǒng)也是這樣,如果我們的微服務(wù)部署在Docker容器中,那么我們需要安裝cAdvisor組件來(lái)監(jiān)控Docker相關(guān)數(shù)據(jù)指標(biāo),如果要采集系統(tǒng)環(huán)境數(shù)據(jù),那么需要安裝 Node Exporter 組件,而且告警組件也是和Prometheus分開(kāi)的,如果需要告警功能,同樣需要安裝Alertmanager組件,這一連串組件的組合,我們可以使用docker-compose來(lái)安裝我們需要所有組件。
這里只做簡(jiǎn)單介紹,不搞這么復(fù)雜了。prometheus都可以支持
我們可以在應(yīng)用端安裝下列組件,
- cadvisor用于監(jiān)控Docker相關(guān)數(shù)據(jù)指標(biāo);
- Alertmanager用于告警管理;
- snmp_exporter用于監(jiān)控網(wǎng)絡(luò)設(shè)備;
- node-exporter用于采集本機(jī)數(shù)據(jù);
- mysqld_exporter用于監(jiān)控mysql服務(wù);
更多exporter可在prometheus官網(wǎng)下載
3.3.1 下載安裝Prometheus
3.3.2 下載安裝Grafana
3.3.3 安裝成功后訪問(wèn)鏈接查看是否成功
- Prometheus: http://192.168.0.10:9090/

- Grafana:http://192.168.0.10:3000/

3.3.4 微服務(wù)相關(guān)配置及添加Prometheus支持
-
微服務(wù)引入prometheus依賴(lài)
...... <!-- prometheus微服務(wù)監(jiān)控--> ...... <!-- actuator prometheus 健康檢查 --> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> <version>1.5.14</version> </dependency> -
開(kāi)啟prometheus抓取端點(diǎn)
# 性能監(jiān)控端點(diǎn)配置 management: security: enabled: true role: ACTUATOR_ADMIN endpoint: health: show-details: always endpoints: enabled-by-default: true web: base-path: /actuator exposure: include: '*' metrics: tags: application: ${spring.application.name} export: prometheus: enabled: true server: servlet: context-path: /actuator health: mail: enabled: false
3.3.5 配置Prometheus
1、編輯prometheus配置文件prometheus.yml,設(shè)置采集微服務(wù)端點(diǎn)scrape_configs:
scrape_configs:
- job_name: 'actuator-gitegg'
basic_auth:
username: user
password: password
scrape_interval: 15s
scrape_timeout: 10s
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['192.168.0.2:80','192.168.0.2:8002']
- basic_auth:設(shè)置采集端點(diǎn)的basic認(rèn)證信息
- metrics_path:設(shè)置prometheus采集端點(diǎn)的路徑
- static_configs.targets: 設(shè)置prometheus采集端點(diǎn)的地址
2、重啟prometheus,訪問(wèn)界面status -> targets,查看采集端點(diǎn)狀態(tài)。

3.3.6 配置Grafana,添加prometheus數(shù)據(jù)源并展示JVM監(jiān)控圖表
