Spring Boot Actuator監(jiān)控的簡(jiǎn)單使用方法示例代碼詳解
Spring Boot Actuator幫助我們實(shí)現(xiàn)了許多中間件比如mysql、es、redis、mq等中間件的健康指示器。
通過 Spring Boot 的自動(dòng)配置,這些指示器會(huì)自動(dòng)生效。當(dāng)這些組件有問題的時(shí)候,HealthIndicator 會(huì)返回 DOWN 或 OUT_OF_SERVICE 狀態(tài),health 端點(diǎn) HTTP 響應(yīng)狀態(tài)碼也會(huì)變?yōu)?503,我們可以以此來配置程序健康狀態(tài)監(jiān)控報(bào)警。
使用步驟也非常簡(jiǎn)單,這里演示的是線程池的監(jiān)控。模擬線程池滿了狀態(tài)下將HealthInicator指示器變?yōu)镈own的狀態(tài)。
pom中引入jar
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
引入properties配置
spring.application.name=boot
# server.servlet.context-path=/boot
# management.server.servlet.context-path=/boot
# JVM (Micrometer)要求給應(yīng)用設(shè)置commonTag
management.metrics.tags.application=${spring.application.name}
#去掉重復(fù)的metrics
spring.metrics.servo.enabled=false
management.endpoint.metrics.enabled=true
management.endpoint.metrics.sensitive=false
#顯式配置不需要權(quán)限驗(yàn)證對(duì)外開放的端點(diǎn)
management.endpoints.web.exposure.include=*
management.endpoints.jmx.exposure.include=*
management.endpoint.health.show-details=always
#Actuator 的 Web 訪問方式的根地址為 /actuator,可以通過 management.endpoints.web.base-path 參數(shù)進(jìn)行修改
management.endpoints.web.base-path=/actuator
management.metrics.export.prometheus.enabled=true
代碼
/**
* @Author jeffSmile
* @Date 下午 6:10 2020/5/24 0024
* @Description 定義一個(gè)接口,來把耗時(shí)很長(zhǎng)的任務(wù)提交到這個(gè) demoThreadPool 線程池,以模擬線程池隊(duì)列滿的情況
**/
@GetMapping("slowTask")
public void slowTask() {
ThreadPoolProvider.getDemoThreadPool().execute(() -> {
try {
TimeUnit.HOURS.sleep(1);
} catch (InterruptedException e) {
}
});
}
package com.mongo.boot.service;
import jodd.util.concurrent.ThreadFactoryBuilder;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolProvider {
//一個(gè)工作線程的線程池,隊(duì)列長(zhǎng)度10
private static ThreadPoolExecutor demoThreadPool = new ThreadPoolExecutor(
1, 1,
2, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(10),
new ThreadFactoryBuilder().setNameFormat("demo-threadpool-%d").get());
//核心線程數(shù)10,最大線程數(shù)50的線程池,隊(duì)列長(zhǎng)度50
private static ThreadPoolExecutor ioThreadPool = new ThreadPoolExecutor(
10, 50,
2, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(100),
new ThreadFactoryBuilder().setNameFormat("io-threadpool-%d").get());
public static ThreadPoolExecutor getDemoThreadPool() {
return demoThreadPool;
}
public static ThreadPoolExecutor getIOThreadPool() {
return ioThreadPool;
}
}
package com.mongo.boot.service;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ThreadPoolExecutor;
/**
* @Author jeffSmile
* @Date 下午 6:12 2020/5/24 0024
* @Description 自定義的 HealthIndicator 類,用于單一線程池的健康狀態(tài)
**/
public class ThreadPoolHealthIndicator implements HealthIndicator {
private ThreadPoolExecutor threadPool;
public ThreadPoolHealthIndicator(ThreadPoolExecutor threadPool) {
this.threadPool = threadPool;
}
@Override
public Health health() {
//補(bǔ)充信息
Map<String, Integer> detail = new HashMap<>();
//隊(duì)列當(dāng)前元素個(gè)數(shù)
detail.put("queue_size", threadPool.getQueue().size());
//隊(duì)列剩余容量
detail.put("queue_remaining", threadPool.getQueue().remainingCapacity());
//如果還有剩余量則返回UP,否則返回DOWN
if (threadPool.getQueue().remainingCapacity() > 0) {
return Health.up().withDetails(detail).build();
} else {
return Health.down().withDetails(detail).build();
}
}
}
package com.mongo.boot.service;
import org.springframework.boot.actuate.health.CompositeHealthContributor;
import org.springframework.boot.actuate.health.HealthContributor;
import org.springframework.boot.actuate.health.NamedContributor;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/***
* @Author jeffSmile
* @Date 下午 6:13 2020/5/24 0024
* @Description 定義一個(gè) CompositeHealthContributor,來聚合兩個(gè) ThreadPoolHealthIndicator 的實(shí)例,
* 分別對(duì)應(yīng) ThreadPoolProvider 中定義的兩個(gè)線程池
**/
@Component
public class ThreadPoolsHealthContributor implements CompositeHealthContributor {
//保存所有的子HealthContributor
private Map<String, HealthContributor> contributors = new HashMap<>();
ThreadPoolsHealthContributor() {
//對(duì)應(yīng)ThreadPoolProvider中定義的兩個(gè)線程池
this.contributors.put("demoThreadPool", new ThreadPoolHealthIndicator(ThreadPoolProvider.getDemoThreadPool()));
this.contributors.put("ioThreadPool", new ThreadPoolHealthIndicator(ThreadPoolProvider.getIOThreadPool()));
}
@Override
public HealthContributor getContributor(String name) {
//根據(jù)name找到某一個(gè)HealthContributor
return contributors.get(name);
}
@Override
public Iterator<NamedContributor<HealthContributor>> iterator() {
//返回NamedContributor的迭代器,NamedContributor也就是Contributor實(shí)例+一個(gè)命名
return contributors.entrySet().stream()
.map((entry) -> NamedContributor.of(entry.getKey(), entry.getValue())).iterator();
}
}
啟動(dòng)springboot驗(yàn)證
這里我訪問:http://localhost:8080/slowTask

每次訪問都向demo線程池中提交一個(gè)耗時(shí)1小時(shí)的任務(wù),而demo線程池的核心和最大線程數(shù)都是1,隊(duì)列長(zhǎng)度為10,那么當(dāng)訪問11次之后,任務(wù)將被直接拒絕掉!


此時(shí)訪問:http://localhost:8080/actuator/health

demo線程池隊(duì)列已經(jīng)滿了,狀態(tài)變?yōu)镈OWN。

監(jiān)控內(nèi)部重要組件的狀態(tài)數(shù)據(jù)
通過 Actuator 的 InfoContributor 功能,對(duì)外暴露程序內(nèi)部重要組件的狀態(tài)數(shù)據(jù)!
實(shí)現(xiàn)一個(gè) ThreadPoolInfoContributor 來展現(xiàn)線程池的信息:
package com.mongo.boot.config;
import com.mongo.boot.service.ThreadPoolProvider;
import org.springframework.boot.actuate.info.Info;
import org.springframework.boot.actuate.info.InfoContributor;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ThreadPoolExecutor;
/**
* @Author jeffSmile
* @Date 下午 6:37 2020/5/24 0024
* @Description 通過 Actuator 的 InfoContributor 功能,對(duì)外暴露程序內(nèi)部重要組件的狀態(tài)數(shù)據(jù)
**/
@Component
public class ThreadPoolInfoContributor implements InfoContributor {
private static Map threadPoolInfo(ThreadPoolExecutor threadPool) {
Map<String, Object> info = new HashMap<>();
info.put("poolSize", threadPool.getPoolSize());//當(dāng)前池大小
info.put("corePoolSize", threadPool.getCorePoolSize());//設(shè)置的核心池大小
info.put("largestPoolSize", threadPool.getLargestPoolSize());//最大達(dá)到過的池大小
info.put("maximumPoolSize", threadPool.getMaximumPoolSize());//設(shè)置的最大池大小
info.put("completedTaskCount", threadPool.getCompletedTaskCount());//總完成任務(wù)數(shù)
return info;
}
@Override
public void contribute(Info.Builder builder) {
builder.withDetail("demoThreadPool", threadPoolInfo(ThreadPoolProvider.getDemoThreadPool()));
builder.withDetail("ioThreadPool", threadPoolInfo(ThreadPoolProvider.getIOThreadPool()));
}
}
直接訪問http://localhost:8080/actuator/info

如果開啟jmx,還可以使用jconsole來查看線程池的狀態(tài)信息:
#開啟 JMX spring.jmx.enabled=true
打開jconcole界面之后,進(jìn)入MBean這個(gè)tab,可以在EndPoint下的Info操作這里看到我們的Bean信息。

不過,除了jconsole之外,我們可以把JMX協(xié)議轉(zhuǎn)為http協(xié)議,這里引入jolokia:
<dependency> <groupId>org.jolokia</groupId> <artifactId>jolokia-core</artifactId> </dependency>
重啟后訪問:http://localhost:8080/actuator/jolokia/exec/org.springframework.boot:type=Endpoint,name=Info/info

監(jiān)控延伸
通過Micrometer+promethues+grafana的組合也可以進(jìn)行一些生產(chǎn)級(jí)別的實(shí)踐。
到此這篇關(guān)于Spring Boot Actuator監(jiān)控的簡(jiǎn)單使用的文章就介紹到這了,更多相關(guān)Spring Boot Actuator監(jiān)控內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Springboot調(diào)整接口響應(yīng)返回時(shí)長(zhǎng)詳解(解決響應(yīng)超時(shí)問題)
當(dāng)后端對(duì)于數(shù)據(jù)量較大的處理或是某些耗時(shí)的操作時(shí),需要先對(duì)請(qǐng)求接口的請(qǐng)求進(jìn)行響應(yīng),下面這篇文章主要給大家介紹了關(guān)于Springboot調(diào)整接口響應(yīng)返回時(shí)長(zhǎng)(解決響應(yīng)超時(shí)問題)的相關(guān)資料,需要的朋友可以參考下2023-01-01
java開發(fā)的工廠方法模式及抽象工廠驗(yàn)證示例
這篇文章主要為大家介紹了java開發(fā)中的工廠方法模式以及抽象工廠的驗(yàn)證示例,有需要的朋友可以借鑒參考下希望能夠有所幫助祝大家多多進(jìn)步2021-10-10
利用Springboot實(shí)現(xiàn)Jwt認(rèn)證的示例代碼
這篇文章主要介紹了利用Springboot實(shí)現(xiàn)Jwt認(rèn)證的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
Object.wait()與Object.notify()的用法詳細(xì)解析
以下是對(duì)java中Object.wait()與Object.notify()的用法進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過來參考下2013-09-09
Spring Security和Shiro的相同點(diǎn)與不同點(diǎn)整理
在本篇文章里小編給大家整理的是關(guān)于Spring Security和Shiro的相同不同點(diǎn)整理,需要的朋友們可以參考下。2020-02-02
java基礎(chǔ)之 Arrays.toString()方法詳解
這篇文章主要介紹了java基礎(chǔ)之 Arrays.toString()方法詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-02-02
SpringBoot登錄驗(yàn)證token攔截器的實(shí)現(xiàn)
本文主要介紹了SpringBoot登錄驗(yàn)證token攔截器的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07

