SpringBoot生产监控

news/2024/5/6 19:36:22/文章来源:https://blog.csdn.net/lemon_TT/article/details/127089969

文章目录

  • 一、健康监控简介
    • 1、介绍
    • 2、SpringBoot准备工作
    • 3、其他
  • 二、健康检测触达关键组件
    • 1、内置组件健康详情
    • 2、自定义组件健康详情
    • 3、自定义多 HealthIndicator 聚合
  • 三、对外暴露应用内部重要组件的状态
    • 1、内部状态数据暴露
    • 2、JMX MBean
  • 四、指标 Metrics 快速定位
  • 五、总结

一、健康监控简介

1、介绍

开发完成后,生产就绪需要做哪些工作呢?我认为,以下三方面的工作最重要。

  • 提供健康检测接口。传统采用 ping 的方式对应用进行探活检测并不准确。有的时候,应用的关键内部或外部依赖已经离线,导致其根本无法正常工作,但其对外的 Web 端口或管理端口是可以 ping 通的。我们应该提供一个专有的监控检测接口,并尽可能触达一些内部组件。

  • 暴露应用内部信息。应用内部诸如线程池、内存队列等组件,往往在应用内部扮演了重要的角色,如果应用或应用框架可以对外暴露这些重要信息,并加以监控,那么就有可能在诸如 OOM 等重大问题暴露之前发现蛛丝马迹,避免出现更大的问题。

  • 建立应用指标 Metrics 监控。Metrics 可以翻译为度量或者指标,指的是对于一些关键信息以可聚合的、数值的形式做定期统计,并绘制出各种趋势图表。这里的指标监控,包括两个方面:一是,应用内部重要组件的指标监控,比如 JVM 的一些指标、接口的 QPS 等;二是,应用的业务数据的监控,比如电商订单量、游戏在线人数等。

2、SpringBoot准备工作

Spring Boot 有一个 Actuator 模块,封装了诸如健康检测、应用内部信息、Metrics 指标等生产就绪的功能。今天这一讲后面的内容都是基于 Actuator 的,因此我们需要先完成 Actuator 的引入和配置

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Actuator 自带了很多开箱即用提供信息的端点(Endpoint),可以通过** JMX 或 Web **两种方式进行暴露。考虑到有些信息比较敏感,这些内置的端点默认不是完全开启的,你可以通过官网查看这些默认值。在这里,为了方便后续 Demo,我们设置所有端点通过 Web 方式开启。

默认情况下,Actuator 的 Web 访问方式的根地址为 /actuator,可以通过management.endpoints.web.base-path 参数进行修改

management:server:port: 45678endpoints:web:exposure:include: "*"base-path: /admin

现在访问http://localhost:45678/admin可以查看 Actuator 的所有功能 URL

3、其他

大部分端点提供的是只读信息,比如查询 Spring 的 Bean、ConfigurableEnvironment、定时任务、SpringBoot 自动配置、Spring MVC 映射等;少部分端点还提供了修改功能,比如优雅关闭程序、下载线程 Dump、下载堆 Dump、修改日志级别等。

我们可以访问这里,查看所有这些端点的功能,详细了解它们提供的信息以及实现的操作。此外推荐一个很好的工具, Spring Boot 管理工具Spring Boot Admin,它把大部分 Actuator 端点提供的功能封装为了 Web UI。可以参考:Spring Boot Admin服务监控

二、健康检测触达关键组件

1、内置组件健康详情

健康检测接口可以让监控系统或发布工具知晓应用的真实健康状态,比 ping 应用端口更可靠。不过,要达到这种效果最关键的是,我们能确保健康检测接口可以探查到关键组件的状态。好在 Spring Boot Actuator帮我们预先实现了诸如数据库、InfluxDB、Elasticsearch、Redis、RabbitMQ 等三方系统的健康检测指示器 HealthIndicator。

通过 Spring Boot 的自动配置,这些指示器会自动生效。当这些组件有问题的时候,HealthIndicator 会返回 DOWN OUT_OF_SERVICE 状态,health 端点 HTTP 响应状态码也会变为 503,我们可以以此来配置程序健康状态监控报警。

management:server:port: 45678endpoints:web:exposure:include: "*"base-path: /adminendpoint:health:show-details: always

我们可以修改配置文件,把 management.endpoint.health.show-details 参数设置为 always,让所有用户都可以直接查看各个组件的健康情况(如果配置为 when-authorized,那么可以结合 management.endpoint.health.roles 配置授权的角色)。访问 health 端点可以看到,数据库、磁盘、RabbitMQ、Redis 等组件健康状态是 UP,整个应用的状态也是 UP

2、自定义组件健康详情

如果程序依赖一个很重要的三方服务,我们希望这个服务无法访问的时候,应用本身的健康状态也是 DOWN,首先创建User类以及配置bean

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {private long userId;private String userName;
}@Configuration
public class Config {@Beanpublic RestTemplate restTemplate(){return new RestTemplate();}
}

比如三方服务有一个 user 接口,出现异常的概率是 50%:

@Slf4j
@RestController
@RequestMapping("user")
public class UserServiceController {@GetMappingpublic User getUser(@RequestParam("userId") long id) {//一半概率返回正确响应,一半概率抛异常if (ThreadLocalRandom.current().nextInt() % 2 == 0) {return new User(id, "name" + id);} else {throw new RuntimeException("error");}}
}

要实现这个 user 接口是否正确响应和程序整体的健康状态挂钩的话,很简单,只需定义一个 UserServiceHealthIndicator实现 HealthIndicator接口即可。

在 health 方法中,我们通过 RestTemplate 来访问这个 user 接口,如果结果正确则返回 Health.up(),并把调用执行耗时和结果作为补充信息加入 Health 对象中。如果调用接口出现异常,则返回 Health.down(),并把异常信息作为补充信息加入 Health 对象中:

@Component
@Slf4j
public class UserServiceHealthIndicator implements HealthIndicator {@Autowiredprivate RestTemplate restTemplate;@Overridepublic Health health() {long begin = System.currentTimeMillis();long userId = 2L;User user = null;try {user = restTemplate.getForObject("http://localhost:8080/user?userId=" + userId, User.class);if (user != null && user.getUserId() == userId) {return Health.up().withDetail("user", user).withDetail("took", System.currentTimeMillis() - begin).build();} else {return Health.down().withDetail("took", System.currentTimeMillis() - begin).build();}} catch (Exception ex) {log.warn("health check failed!", ex);return Health.down(ex).withDetail("took", System.currentTimeMillis() - begin).build();}}
}

此时访问http://localhost:45678/admin/health即可发现UserService已经成功被检测
在这里插入图片描述

3、自定义多 HealthIndicator 聚合

我们再来看一个聚合多个 HealthIndicator 的案例,也就是定义一个 CompositeHealthContributor 来聚合多个 HealthContributor,实现一组线程池的监控

首先,在 ThreadPoolProvider 中定义两个线程池,其中 demoThreadPool 是包含一个工作线程的线程池,类型是 ArrayBlockingQueue,阻塞队列的长度为 10;还有一个 ioThreadPool 模拟 IO 操作线程池,核心线程数 10,最大线程数 50

public class ThreadPoolProvider {//一个工作线程的线程池,队列长度10private static ThreadPoolExecutor demoThreadPool = new ThreadPoolExecutor(1, 1,2, TimeUnit.SECONDS,new ArrayBlockingQueue<>(10),new CustomizableThreadFactory("springThread-pool-"));//核心线程数10,最大线程数50的线程池,队列长度50private static ThreadPoolExecutor ioThreadPool = new ThreadPoolExecutor(10, 50,2, TimeUnit.SECONDS,new ArrayBlockingQueue<>(100),new CustomizableThreadFactory("io-Thread-pool-"));public static ThreadPoolExecutor getDemoThreadPool() {return demoThreadPool;}public static ThreadPoolExecutor getIOThreadPool() {return ioThreadPool;}}

然后,我们定义一个接口,来把耗时很长的任务提交到这个 demoThreadPool 线程池,以模拟线程池队列满的情况:

@GetMapping("slowTask")public void slowTask() {ThreadPoolProvider.getDemoThreadPool().execute(() -> {try {TimeUnit.HOURS.sleep(1);} catch (InterruptedException e) {}});}

做了这些准备工作后,让我们来真正实现自定义的 HealthIndicator 类,用于单一线程池的健康状态。我们可以传入一个 ThreadPoolExecutor,通过判断队列剩余容量来确定这个组件的健康状态,有剩余量则返回 UP,否则返回 DOWN,并把线程池队列的两个重要数据,也就是当前队列元素个数和剩余量,作为补充信息加入 Health

public class ThreadPoolHealthIndicator implements HealthIndicator {private ThreadPoolExecutor threadPool;public ThreadPoolHealthIndicator(ThreadPoolExecutor threadPool) {this.threadPool = threadPool;}@Overridepublic Health health() {Map<String, Integer> detail = new HashMap<>();detail.put("queue_size", threadPool.getQueue().size());detail.put("queue_remaining", threadPool.getQueue().remainingCapacity());if (threadPool.getQueue().remainingCapacity() > 0) {return Health.up().withDetails(detail).build();} else {return Health.down().withDetails(detail).build();}}
}

再定义一个 CompositeHealthContributor,来聚合两个 ThreadPoolHealthIndicator 的实例,分别对应 ThreadPoolProvider 中定义的两个线程池:

@Component
public class ThreadPoolsHealthContributor implements CompositeHealthContributor {private Map<String, HealthContributor> contributors = new HashMap<>();ThreadPoolsHealthContributor() {this.contributors.put("demoThreadPool", new ThreadPoolHealthIndicator(ThreadPoolProvider.getDemoThreadPool()));this.contributors.put("ioThreadPool", new ThreadPoolHealthIndicator(ThreadPoolProvider.getIOThreadPool()));}@Overridepublic HealthContributor getContributor(String name) {return contributors.get(name);}@Overridepublic Iterator<NamedContributor<HealthContributor>> iterator() {return contributors.entrySet().stream().map((entry) -> NamedContributor.of(entry.getKey(), entry.getValue())).iterator();}
}

启动后当看到一个 demoThreadPool 为 DOWN 导致父 threadPools 为 DOWN,进一步导致整个程序的 status 为 DOWN:

三、对外暴露应用内部重要组件的状态

1、内部状态数据暴露

除了可以把线程池的状态作为整个应用程序是否健康的依据外,我们还可以通过 Actuator 的 InfoContributor 功能,对外暴露程序内部重要组件的状态数据

@Component
public class ThreadPoolInfoContributor implements InfoContributor {private static Map threadPoolInfo(ThreadPoolExecutor threadPool) {Map<String, Object> info = new HashMap<>();info.put("poolSize", threadPool.getPoolSize());info.put("corePoolSize", threadPool.getCorePoolSize());info.put("largestPoolSize", threadPool.getLargestPoolSize());info.put("maximumPoolSize", threadPool.getMaximumPoolSize());info.put("completedTaskCount", threadPool.getCompletedTaskCount());return info;}@Overridepublic void contribute(Info.Builder builder) {builder.withDetail("demoThreadPool", threadPoolInfo(ThreadPoolProvider.getDemoThreadPool()));builder.withDetail("ioThreadPool", threadPoolInfo(ThreadPoolProvider.getIOThreadPool()));}
}

访问 /admin/info 接口,可以看到这些数据

2、JMX MBean

如果开启了JMX,即spring.jmx.enabled=true,可以通过 jconsole 工具,在 org.springframework.boot.Endpoint 中找到 Info 这个 MBean,然后执行 info 操作可以看到,我们刚才自定义的 InfoContributor 输出的有关两个线程池的信息:

在这里插入图片描述

四、指标 Metrics 快速定位

指标是指一组和时间关联的、衡量某个维度能力的量化数值。通过收集指标并展现为曲线图、饼图等图表,可以帮助我们快速定位、分析问题

五、总结

健康检测可以帮我们实现负载均衡的联动;应用信息以及 Actuaor 提供的各种端点,可以帮我们查看应用内部情况,甚至对应用的一些参数进行调整;而指标监控,则有助于我们整体观察应用运行情况,帮助我们快速发现和定位问题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_15650.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

String字符串拼接原理

前言 明白什么是引用&#xff0c;什么是该引用指向的真正对象。 对于基本数据类型比较的是值&#xff0c;对于引用数据类型比较的是指向的对象的地址&#xff0c;即两者指向的是否是同一个对象。 String s "gzc";上述代码中s为变量引用&#xff0c;它存在于栈中&am…

JAVA毕设项目商店管理系统(java+VUE+Mybatis+Maven+Mysql)

JAVA毕设项目商店管理系统&#xff08;javaVUEMybatisMavenMysql&#xff09; 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技…

wordpress字体个性化插件

wordpress字体插件可以对我们发布的文档字体大小、颜色、以及繁体简体进行切换。整洁的页面有助于提升用户阅读体验。wordpress字体插件具有可视化的字体修改页面&#xff0c;可以让我们调整出自己中意的文字&#xff0c;打造属于自己的个性化WordPress。 wordpress字体插件不需…

【Java】ArrayList和LinkedList区别?想秒懂就进来看!

ArrayList和LinkedList区别&#xff1f;1.底层结构不同2.ArrayList 和 LinkedList 都实现了 List 接口3.查询的对比4.添加的对比4.1 ArrayList 的添加操作4.1.1 在最后的位置添加元素4.1.2 在指定位置添加元素4.2 LinkedList 的添加操作5.总结5.1 以下情况使用 ArrayList5.2 以…

NXP i.MX 8M Mini开发板(4核 ARM Cortex-A53)硬件原理图规格说明书

前 言 本文档主要介绍NXP i.MX 8M Mini开发板硬件接口资源以及设计注意事项等内容。 创龙科技的NXP i.MX 8M Mini开发板是一款基于NXP i.MX 8M Mini的四核ARM Cortex-A53 + 单核ARM Cortex-M4异构多核处理器设计的高性能开发板,由核心板和评估底板组成。ARM Cortex-A53(64-b…

SMA2.92高频连接器的主要特点​

SMA2.92高频连接器的主要特点 2.92mm连接器的名称是以其外导体内径命名的&#xff0c;采用空气介质工作频率高达40GHz,可与SMA和3.5mm连接器互换对插。优越的电性能、可靠的连接尤其适用于测试系统和武*装备&#xff0c;成为国际上应用最为广泛的毫米微波连接器之一。 SMA2.92高…

[游戏开发][unity]Xlua中使用proto、json、lpeg

Xlua官方教程里有&#xff0c;在创建lua虚拟机时&#xff0c;可以添加3个处理数据的库 _luaEnv new LuaEnv(); _luaEnv.AddLoader(CustomLoaderMethod); _luaEnv.AddBuildin("rapidjson", XLua.LuaDLL.Lua.LoadRapidJson); _luaEnv.AddBuildin("lpeg", X…

零基础学SQL(一、数据库与SQL简介)

一、数据库(database)是什么 目录 一、数据库(database)是什么 二、数据库专业术语 三、常见数据库类型 四、什么是SQL 五、为什么要学习SQL 我们从百度词条中可以看到&#xff0c;百度对数据库的介绍如下&#xff1a; 数据库是“按照数据结构来组织、存储和管理…

RabbitMQ总结

一、简介 什么是 MQ MQ Message Queue 消息队列 消息队列&#xff1a;存放内容是消息的 FIFO&#xff08;先入先出&#xff09; 队列。是一种跨进程的通信机制&#xff0c;用于上下游传递消息。 为什么要用 MQ &#xff1f;作用 1、应用解耦 以电商系统为例&#xff0c…

玻色量子荣获第二届“率先杯”未来技术创新大赛“决赛优胜奖”

​9月22日至23日&#xff0c;由中国科学院、深圳市人民政府联合主办的第二届“率先杯”未来技术创新大赛决赛在深圳、北京两地以“线上线下结合”的形式成功举办。大赛组委会办公室秘书处组织专家按照《大赛评审方案》对进入决赛的项目进行评审&#xff0c;经择优遴选&#xff…

vue3项目创建并运行

vue搭建 准备环境 npmnodewebpackvs code npm 使用brew命令行进行下载安装指定版本&#xff1a; brew install npm查看版本号&#xff1a; $ npm -v 8.15.0Node 进入官网nodejs&#xff0c;根据自己电脑的版本进行下载安装&#xff0c;如果是mac电脑&#xff0c;可以直接…

分布式文件存储系统MinIO笔记

文章目录一、MinIO介绍1、文件系统应用场景2、MinIO介绍3、MinIO优点4、MinIO的基础概念5、纠删码EC&#xff08;Erasure Code&#xff09;6、存储形式7、存储方案二、Minio环境搭建1、介绍2、单机部署2.1 单机部署2.2 基于Linux部署2.3 基于docker部署(推荐)3、minio 纠删码模…

塑料划分PP PE PS PA ABS PVC

**PET&#xff08;聚酯&#xff09;代号1&#xff0c; **又叫涤纶树脂&#xff0c;原料呈乳白色或浅黄色&#xff0c;透明性好&#xff0c;无毒&#xff0c;具有密度高&#xff0c;硬度高&#xff0c;耐磨损&#xff0c;但不耐热水侵泡&#xff0c;不耐碱等特点&#xff0c;使…

2022年暨南大学计算机830真题

学科、专业名称&#xff1a;网络空间安全 研究方向&#xff1a;网络空间安全083900 考试科目名称及代码&#xff1a;数据结构830 考生注意&#xff1a;所有答案必须写在答题纸(卷)上&#xff0c;写在本试题上一律不给分。 一、 单项选择题 (每题2分&#xff0c;共20分) 下列程…

[python刷题模板] 珂朵莉树 ODT (基于支持随机访问的跳表

[python刷题模板] 珂朵莉树 ODT &#xff08;基于支持随机访问的跳表&#xff09; 一、 算法&数据结构1. 描述2. 复杂度分析3. 常见应用4. 常用优化二、 模板代码0. 区间推平(lg)&#xff0c;单点询问(lg) CF292E. Copying Data1. 区间推平&#xff0c;区间询问最小值2. 区…

Unity Lighting 面板的参数设置用途详细总结

一、Environment 环境光 二、Scene 1、如果选择生成LightMap 要关闭实时光&#xff0c;开启烘培光 lighting mode为Mixed时&#xff0c;lighting settings的Mixed Lighting可用于设置混合的方式&#xff1a;Baked Indirect mode提供最高质量的光照&#xff0c;其设置只牵扯间…

windows环境下elasticsearch使用教程

windows环境下elasticsearch使用教程如下&#xff1a; 一、首先安装jdkElasticSearch是基于lucence开发的&#xff0c;lucence是apache开发的&#xff0c;因此ElasticSearch运行环境就需要java jdk支持。所以要先安装JAVA环境。由于ElasticSearch 5.x 往后依赖于JDK 1.8的&…

HAPPE+ER:一款让脑电研究人员“更快乐”的软件,可用于事件相关电位(ERP)分析的标准化预处理管道

导读 事件相关电位(ERP)设计是用脑电图(EEG)检测神经认知功能的常用方法。然而&#xff0c;传统的ERP数据预处理方法是手动编辑&#xff0c;这是一个主观且耗时的过程。最近创建了许多自动化通道&#xff0c;以满足EEG数据预处理的标准化、自动化和量化的需求&#xff1b;然而…

知识经济时代的基石:知识协同

管理学家彼得德鲁克&#xff08;1994&#xff09;指出&#xff1a;“企业管理的本质不在于技术与程序&#xff0c;而在于使知识有效。”在知识占主导地位的社会里&#xff0c;企业依靠知识进行创新的能力代表了企业在竞争中的优势&#xff0c;也是企业成功与否的标志。 世界变…

C++——string的封装

参考string类完成my_string类 #include <iostream> #include<cstring> using namespace std; class my_string { private:char *str;int len; public://无参构造my_string(){len 15;str new char[len];cout<<"无参构造"<<endl;}//有参构造…