徹底搞懂Spring Boot的系統(tǒng)監(jiān)控機制
在 Java 世界中,Spring 框架已經是最主流的開發(fā)框架了。但傳統(tǒng) Spring 框架存在一個明顯的問題,那就是 缺少系統(tǒng)監(jiān)控功能。如果想要獲取一個 Spring 應用程序的線程工作狀態(tài)以及 JVM 性能指標等各種運行時數(shù)據(jù),我們就不得不借助一些第三方工具,這在云原生時代無疑加重了系統(tǒng)運維管理的成本。
好在,Spring Boot 框架誕生了,它不僅繼承了 Spring 框架原有的優(yōu)良特性,而且又引入了一個創(chuàng)新型的技術組件,即 Spring Boot Actuator,該組件可以用來實現(xiàn)內嵌的系統(tǒng)監(jiān)控功能,完美地解決了原有 Spring 框架缺少系統(tǒng)監(jiān)控功能的問題。讓我們一起來看一下吧!
Spring Boot Actuator
Actuator 組件是 Spring Boot 中承載系統(tǒng)監(jiān)控功能的組件,該組件通過一系列 HTTP 端點提供監(jiān)控能力。Spring Boot 的強大之處就在于為開發(fā)人員內置了一組非常簡單而實用的原生監(jiān)控端點。在接下來的內容中,我們先介紹一些常用的 Actuator 端點。
原生 Actuator 端點
說到監(jiān)控端點,你可能會覺得這個概念有點兒抽象。實際上,所謂的監(jiān)控端點,就是一個普通的 HTTP 請求地址。當我們啟動一個 Spring Boot 應用程序,可以訪問 http://localhost:8080/actuator 這個 HTTP 地址來獲取所有可用的端點信息。
{
"_links":{
"self":{
"href":"http://localhost:8080/actuator",
"templated":false
},
"health-path":{
"href":"http://localhost:8080/actuator/health/{*path}",
"templated":true
},
"health":{
"href":"http://localhost:8080/actuator/health",
"templated":false
},
"info":{
"href":"http://localhost:8080/actuator/info",
"templated":false
}
}
}
可以看到,這些都是 HATEOAS 風格的 HTTP 端點信息。我們在這里找到了兩個非常常用的端點,即 health 端點和 info 端點。以 health 端點為例,我們可以通過該端點進一步獲取系統(tǒng)的健康狀態(tài)信息。
{
"status":"UP",
"components":{
"diskSpace":{
"status":"UP",
"details":{
"total":201649549312,
"free":3434250240,
"threshold":10485760
}
},
"ping":{
"status":"UP"
}
}
}
可以看到,這里展示了當前系統(tǒng)的磁盤空間系統(tǒng)以及網絡連接信息。事實上,在 Spring Boot Actuator 中包含了一組類似 health 端點的監(jiān)控端點。我們可以把這些端點按照各自提供的功能進行分類,包括應用配置、度量指標和操作控制這三大類。
圖 1 Spring Boot Actuator 的三大類原生端點
其中,應用配置類端點的作用就是提供各種 Spring Boot 應用程序相關的配置信息,典型的包括/beans、/env、/info 等端點。通過這些端點,開發(fā)人員可以獲取應用程序中所包含的 JavaBean 信息、環(huán)境變量信息以及各種自定義的配置信息等。
圖 2 常見的應用配置類端點
顧名思義,度量指標類的監(jiān)控端點一方面用來獲取內存信息、線程信息等各種重要的度量指標,同時也可以正確反映應用程序的健康指標信息,這部分的常見端點有/metrics、/threaddump 和/health 端點等。
圖 3 常見的度量指標類端點
相比這兩類端點,操作控制類的端點則數(shù)量較少,常見的只有用來對應用程序執(zhí)行關閉操作的/shutdown 端點。
如果 Spring Boot Actuator 默認提供的端點信息不能滿足需求,我們還可以對其進行修改和擴展。常見實現(xiàn)方案有兩種,一種是擴展現(xiàn)有的監(jiān)控端點,另一種是自定義新的監(jiān)控端點。
擴展 Actuator 端點
接下來,我們來關注一下如何在現(xiàn)有的監(jiān)控端點上添加定制化功能。我們同樣以前面已經介紹的/health 端點為例展開討論。
在 Spring Boot 中,Health 端點用于檢查正在運行的應用程序健康狀態(tài)。Health 端點信息的豐富程度取決于當下應用程序所處的環(huán)境,一個現(xiàn)實環(huán)境下的 Health 端點信息如下所示。通過這些信息,我們可以判斷該環(huán)境中包含了 MySQL 數(shù)據(jù)庫。
{
"status":"UP",
"components":{
"db":{
"status":"UP",
"details":{
"database":"MySQL",
"result":1,
"validationQuery":"/* ping */ SELECT 1"
}
},
"diskSpace":{
"status":"UP",
"details":{
"total":201649549312,
"free":3491287040,
"threshold":10485760
}
},
"ping":{
"status":"UP"
}
}
}
現(xiàn)在,我們希望在 Health 端點中暴露某個應用程序的當前運行時狀態(tài)。這時候就可以自定義一個 CustomHealthIndicator 端點。我們明確,健康狀態(tài)信息是由 HealthIndicator 接口從 Spring 的 ApplicationContext 中進行獲取的,所以這個 CustomHealthIndicator 需要實現(xiàn) HealthIndicator 接口。
@Component
publicclass CustomHealthIndicator implements HealthIndicator {
@Override
public Health health() {
try {
URL url = new URL("http://localhost:8083/health/");
HttpURLConnection conn = (HttpURLConnection)
url.openConnection();
int statusCode = conn.getResponseCode();
if (statusCode >= 200 && statusCode < 300) {
return Health.up().build();
} else {
return Health.down().withDetail("HTTP Status Code", statusCode).build();
}
} catch (IOException e) {
return Health.down(e).build();
}
}
}
我們需要提供 health() 方法的具體實現(xiàn)并返回一個 Health 結果對象。該結果對象應該包括一個狀態(tài),并且可以根據(jù)需要添加任何細節(jié)信息。
以上代碼用一種簡單而直接的方式判斷某個服務是否正在運行。我們構建一個 HTTP 請求,然后根據(jù) HTTP 響應得出健康診斷的結論。如果 HTTP 響應的狀態(tài)碼處于 200~300 之間,我們就認為該服務正在運行,Health.up().build() 方法將返回一種 UP 響應,如下所示。
{
"status": "UP",
"details": {
"custom":{
"status": "UP"
}
…
}
}
如果狀態(tài)碼不是處于這個區(qū)間(例如返回的是 404 代表服務不可用)就返回一個 DOWN 響應并給出具體的狀態(tài)碼,如下所示。
{
"status": "DOWN",
"details": {
"custom":{
"status": "DOWN",
"details": {
"HTTP Status Code": "404"
}
},
…
}
}
如果 HTTP 請求直接拋出了異常,我們同樣返回一個 Down 響應,同時把異常信息一起返回,效果如下所示:
{
"status": "DOWN",
"details": {
"custom":{
"status": "DOWN",
"details": {
"error": "java.net.ConnectException: Connection refused: connect"
}
},
…
}
}
顯然,通過擴展 Health 端點為我們實時監(jiān)控系統(tǒng)中各個服務的正常運行狀態(tài)提供了很好的支持,你可以根據(jù)需要構建一系列有用的 HealthIndicator 實現(xiàn)類并添加報警等監(jiān)控手段。
自定義 Actuator 端點
除了對現(xiàn)有的監(jiān)控端點進行動態(tài)擴展,有時候我們還可以根據(jù)業(yè)務場景的需要創(chuàng)建新的監(jiān)控端點。這里舉一個簡單的例子。現(xiàn)在,假設我們的需求是獲取當前操作系統(tǒng)的計算機名稱,那么就可以實現(xiàn)這樣一個新的 CustomEndpoint。
@Configuration
@Endpoint(id = "computername", enableByDefault=true)
public class CustomEndpoint {
@ReadOperation
public Map<String, Object> getMySystemInfo() {
Map<String,Object> result= new HashMap<>();
Map<String, String> map = System.getenv();
result.put("computername",map.get("COMPUTERNAME"));
return result;
}
}
可以看到,CustomEndpoint 通過 System.getenv() 方法獲取了系統(tǒng)的環(huán)境變量,然后再通過環(huán)境變量獲取了計算機名稱。現(xiàn)在,讓我們執(zhí)行這個 CustomEndpoint 端點,得到的結果是這樣的。
{
"computername":"LAPTOP-EQB59J5P"
}
Spring Boot Admin
Spring Boot 還基于 Actuator 組件為開發(fā)人員提供了可視化的系統(tǒng)監(jiān)控組件,這就是 Spring Boot Admin。通過 Admin 組件,我們可以獲取系統(tǒng)運行時的各項關鍵指標,并通過友好的交互界面進行動態(tài)管理。
Spring Boot Admin 會消費前面介紹到的各種 Actuator 的端點信息并將這些信息進行統(tǒng)計和聚合,它的基本原理是這樣的。
圖 4 Spring Boot Admin 基本原理圖
從上圖中,我們首先需要明確存在一個服務器組件 Admin Server,它負責從各個 Admin Client 所暴露的 Actuator 端點中收集各種監(jiān)控信息。注意,這里的 Admin Server 和 Admin Client 本質上都是一個個 Spring Boot 應用程序。然后,Admin Server 會對這些監(jiān)控信息進行加工處理,并最終通過 Web UI 以可視化的效果展示給開發(fā)人員。
Spring Boot Admin 的功能非常強大,包括顯示健康狀態(tài)、JVM、內存等度量明細信息,以及線程、HTTP 跟蹤等監(jiān)控信息。基于 Admin Server,這些功能都通過可視化的 UI 界面進行展示。這里,我截取了幾張效果圖。這是 Admin Server 監(jiān)控信息的主界面。
圖 5 Admin Server 監(jiān)控信息主界面
在這里,我們看到了熟悉的“Health”信息。然后,我們注意到在界面的左下角有一個“JVM”選項,點擊該選項可以獲取與 JVM 相關的監(jiān)控信息。
圖 6 Admin Server 中的 JVM 監(jiān)控信息
最后,我們來看一下非常有用的“Thread Dump”可視化功能。Admin Server 通過這一功能提供了一個連續(xù)性的可視化 Dump 快照信息監(jiān)控界面。
圖 7 Admin Server 中的 Thread Dump 信息
總結
好了,以上就是我這節(jié)課想要和你分享的內容,最后我們來對今天的內容進行一個簡單的梳理吧!
今天我們主要介紹了基于 Spring 產生的 Spring Boot 框架。其中,Spring Boot 內置的 Actuator 組件為開發(fā)人員管理應用程序的運行時狀態(tài)提供了更加直接且高效的手段。
在今天的內容中,我們引入了 Actuator 組件并介紹了該組件所提供的一系列核心端點。更為重要的是,我們還重點分析了如何對 Actuator 端點進行擴展以及創(chuàng)建自定義 Actuator 端點的實現(xiàn)方法。這些實現(xiàn)方法都可以直接應用到日常開發(fā)過程中。而作為延伸,在今天內容的最后,我們還分析了 Spring Boot Admin 這一組件提供的強大可視化監(jiān)控效果。
圖片