手把手教你实现SpringBoot的监控!
任何服务若无监控手段,则等同于完全没有信息;就难以掌握实时运行状态;同样会严重影响问题的有效应对;因此对于每一个服务而言,实现持续有效的管理是不可或缺的任务。
从目前情况来看, 大部分微服务应用都采用了SpringBoot作为基础框架. 因此掌握SpringBoot的监控特性对于提升应用性能至关重要. 同时, SpringBoot提供了若干内置功能和工具来辅助实现对应用程序的全面监控.
本文基于 SpringBoot 2.3.1.RELEASE 版本演示。
SpringBoot 监控
Spring Boot中的实时监控主要包含两种形式:一种是基于HTTP端点的监控方法;另一种则是通过JMX机制实现的应用层面监控。
| HTTP Endpoints 监控
执行器端点支持您监控应用程序并进行交互。SpringBoot提供了丰富的内置资源,并让您能够添加自己的服务接口和功能项。通过HTTP或JMX控制每个功能项的状态,并提供远程访问权限以确保系统的一致性。
每个端点都分配了一个独特的标识符,在访问时可以通过以下路径获取该标识符信息:http://{}:{}:{}{}/(SpringBoot 1.x)。
而在 SpringBoot 2.x 版本中,默认将 /actuator 设为基本路径,在此情况下对应的访问地址则为 http://ip:port/actuator/{id}。
使用 HTTP 监控非常简单,在 SpringBoot 项目中,引入如下依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
代码解读
无需配置即可访问路径 http://localhost:8080/actuator/health;访问后将返回以下结果。

SpringBoot 提供了丰富的默认端点监控功能。然而,在安全性考量下,默认状态下部分端点处于关闭状态。其中关掉功能例如 shutdown 端点就是不可用的状态。
内置端点
SpringBoot 中默认提供的常用内置端点如下:

尽管通常认为这里的大部分端点都是开启状态。而这些默认开放的状态仅限于health和info两个接口。所以为了实现对端点的外部访问权限设置可以通过以下方式来配置参数(若希望所有端点均可访问,则直接将参数设置为星号*)
management:
endpoints:
web:
exposure:
include: [health,info,mappings] //或者直接配置 "*"
代码解读
另外,开启或禁用某一个端点,也可以通过通过如下配置进行动态控制:
management.endpoint.<id>.enabled=true
代码解读
接下来我们挑选几个重点的端点来介绍一下。
health 端点
health 指标默认仅用于显示当前应用程序的健康状态信息 但通过另一个配置我们可以访问更多详细的信息 这不仅能够实时监控当前的应用程序状态 同时也会实时监控与该应用程序相关的第三方服务或应用程序的信息
management:
endpoint:
health:
show-details: always
代码解读
这个配置启动后, 我们将连接至Redis服务器后再重新访问health 端点, 则即可呈现Redis服务的健康状态.

loggers 端点
访问该链接http://localhost:8080/actuator/loggers有助于了解当前应用的运行状态及其详细信息。

这个方面并没有特别突出,并非完全没有价值。然而,在生产环境中,默认的日志级别通常设置为 info 级别,在常规情况下难以找到具体的 bug 位置;但目前出现了一个 bug 难以通过传统的 info 级别来定位问题,并非完全无法排查;于是我们可以暂时将日志级别调整为 debug 来辅助诊断
例如,在上图中所示的情况中, root节点处于info级别.因此,在此情况下,我们可以使用postman等工具发送一个post请求来更新日志记录的级别设置.

修改之后就会发现,日志由原来的 info 变成了 debug:

metrics 端点
metrics 是一个关键的监控端点,它所包含的内容涵盖了 JVM 内存、堆、类加载、处理器和 tomcat 容器等多个重要指标。

可以观察到其中包含有大量的指标参数,任意选择或访问一个指标即可查看与其相关联的具体信息:

自定义监控端点
在上述介绍的基础上可以看出春 Boot 提供的一系列监控功能极为强大。然而即便拥有如此全面且复杂的监控系统仍无法满足每一个人的需求。因此春 Boot 还提供了灵活配置监控接口的能力。
自定义一个监控端点主要有如下常用注解:
@Endpoint: 定义一个监控端点,同时支持 HTTP 和 JMX 两种方式。
@WebEndpoint: 定义一个监控端点,只支持 HTTP 方式。
@JmxEndpoint: 定义一个监控端点,只支持 JMX 方式。
以下三个注解被应用于类中,并标识该类为一个监控端点;此外还有其他注解会被用于方法和参数:
@ReadOperation: 该操作符用于作用于方法,并能够返回端点展示的信息(利用Get方法进行请求)。
@WriteOperation用于方法中以修改端点展示信息(通过Post请求实现)。
@FunctionalOperation:针对方法而言,用于清除对应的端点信息(采用Delete方法进行请求)。
@Selector: 作用在参数上,用来定位一个端点的具体指标路由。
编写一个自定义的监控端点类,并配置 $endpoint 标签用于标识监控操作。通过配置 @ReadOperation 和 @WriteOperation 注解来指定方法的行为类型
@Endpoint(id="myEndpoint")
@Component
public class MyEndpoint {
private String STATUS = "up";
private String DETAIL = "一切正常";
// @ReadOperation
// public String test1(){
// return "wolf";
// }
// @ReadOperation
// public Map<String,String> test2(){
// Map<String,String> map = new HashMap();
// map.put("status","up");
// return map;
// }
@ReadOperation
public JSONObject test3(){
JSONObject jsonObject= new JSONObject();
jsonObject.put("status",STATUS);
jsonObject.put("detail",DETAIL);
return jsonObject;
}
@ReadOperation
public JSONObject test3_1(@Selector String name){
JSONObject jsonObject= new JSONObject();
if ("status".equals(name)){
jsonObject.put("status",STATUS);
}else if ("detail".equals(name)){
jsonObject.put("detail",DETAIL);
}
return jsonObject;
}
@WriteOperation//动态修改指标
public void test4(@Selector String name,@Nullable String value){
if (!StringUtils.isEmpty(value)){
if ("status".equals(name)){
STATUS = value;
}else if ("detail".equals(name)){
DETAIL = value;
}
}
}
}
代码解读
@Component 标签具体说明了将该类交由Spring进行管理的方式;同时还可以通过配置类来加载对应的Bean。
但是当需要将类供第三方使用时
② @ReadOperation 方法可以返回 String 或者 JSONObject 或者 Map 集合等。
在参数中添加了@Selector注释,则意味着当在断点处直接到达子节点时
实现了前面所述的类,并配置并运行了SpringBoot应用程序之后可以直接访问http://localhost:8080/actuator/myEndpoint

同时

该方法可通过 POST 请求进行访问,在操作完成后及时查看即可发现指标已实现动态更新;支持直接传递字符串或JSON格式的数据作为参数输入;也可通过JSON数据的形式传递给该方法进行处理

| JMX 监控
JMX 全称是 Java Management Extensions,被称作 Java 管理扩展。它包含有对 Java 应用程序和 JVM 的全面监控与管理。
借助 JMX 技术我们可以跟踪服务器中主要资源类别及其使用的状态,并观察其内存占用率和 CPU 负载状态。
打开 jdk 下提供的工具 jConsole:

打开之后这里会监控到我们已经启动的应用,双击进入:

如何手动注册一个 JMX MBean?
定义一个接口 SystemInfoMBean(注意名字必须要用 MBean 结尾):
public interface SystemInfoMBean {
int getCpuCore();
long getTotalMemory();
void shutdown();
}
代码解读
重新构造一个类以实现 SystemInfoMBean 接口,并规定其实现类名称确定方式为删除前缀 MBean后的接口名称。
public class SystemInfo implements SystemInfoMBean {
@Override
public int getCpuCore() {
return Runtime.getRuntime().availableProcessors();
}
@Override
public long getTotalMemory() {
return Runtime.getRuntime().totalMemory();
}
@Override
public void shutdown() {
System.exit(0);
}
}
代码解读
最后就是需要将该实现类进行注册:
public class JmxRegisterMain {
public static void main(String[] args) throws NotCompliantMBeanException, InstanceAlreadyExistsException, MBeanRegistrationException, MalformedObjectNameException, IOException {
MBeanServer mBeanServer= ManagementFactory.getPlatformMBeanServer();
ObjectName objectName=new ObjectName("com.lonely.wolf.note.springboot.actuator.jmx:type=SystemInfo");
SystemInfo SystemInfo =new SystemInfo();
mBeanServer.registerMBean(SystemInfo,objectName);//注册
System.in.read();//防止程序结束
}
}
代码解读
运行该 main 方法,再打开 jConsole 就可以看到成功注册了一个 MBean:

在Spring框架中一旦配置了特定的注解属性配置项,比如@Endpoint或者@JmxEndpoint注解项,系统就会自动生成相应的MBean,并且其实其核心原理就是依赖注入机制。
除了自带监控功能外,
还有其他成熟的第三方开源监控工具,
例如 Promethues。
Spring Boot 已对其进行了整合,
在使用时仅需添加以下JAR包即可。
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
代码解读
同时,在配置Prometheus时需要单独进行安装步骤,并且建议采用Prometheus与Grafana结合的方式来建立一个监控系统。在此不做过多介绍,在这里就不做过多介绍。如对这两种工具感兴趣的朋友可自行查阅相关资料学习这些软件的使用方法。
总结
本文着重探讨了Spring Boot Actuator的应用,并详细阐述了其中两种监控机制:HTTP和JMX。最后通过示例展示了如何自定义一个端点,并探讨了手动注册MBean的方法。
