专业的编程技术博客社区

网站首页 > 博客文章 正文

Spring路径-11-SpringBoot应用监控

baijin 2024-09-04 01:49:58 博客文章 6 ℃ 0 评论

1 概述

微服务的特点决定了功能模块的部署是分布式的,大部分功能模块都是运行在不同的机器上,彼此通过服务调用进行交互,前后台的业务流会经过很多个微服务的处理和传递,出现了异常如何快速定位是哪个环节出现了问题?

在这种框架下,微服务的监控显得尤为重要。Spring Boot 给了我们解决方案。通过引入spring-boot-starter-actuator,可以使用Spring Boot为我们提供的准生产环境下的应用监控和管理功能。我们可以通过HTTP,JMX,SSH协议来进行操作,自动得到审计、健康及指标信息等

  • 引入spring-boot-starter-actuator
  • 通过http方式访问监控端点
  • 可进行shutdown(POST 提交,此端点默认关闭)

在Spring boot应用中,要实现可监控的功能,依赖的是 spring-boot-starter-actuator 这个组件。它提供了很多监控和管理你的spring boot应用的HTTP或者JMX端点,并且你可以有选择地开启和关闭部分功能。当你的spring boot应用中引入下面的依赖之后,将自动的拥有审计、健康检查、Metrics监控功能。

SpringBoot Actuator的使用

在Spring boot应用中,要实现可监控的功能,依赖的是 spring-boot-starter-actuator 这个组件。它提供了很多监控和管理你的spring boot应用的HTTP或者JMX端点,并且你可以有选择地开启和关闭部分功能。当你的spring boot应用中引入下面的依赖之后,将自动的拥有审计、健康检查、Metrics监控功能。

pom.xml引入jar包

<!-- web start-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- web end-->
<!-- actuator start-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- actuator end-->

通过下面的配置启用所有的监控端点,默认情况下,这些端点是禁用的;

management:
  endpoints:
    web:
      exposure:
        include: "*"
        # “*”号代表启用所有的监控端点,可以单独启用,例如,`health`,`info`,`metrics`等
#自定义路径
  context-path=/manage

测试访问:http://localhost:9090/manage/metrics



2 端点说明

Endpoints(端点)是暴露给外部访问的一系列接口,它们提供了关于应用程序内部状态、配置和指标的各种信息。这些端点对于监控应用健康状况、性能调试和管理配置至关重要。

2.1 端点的作用和功能

Actuator端点主要用于实现以下功能:

  • 提供应用程序的健康检查,包括数据库连接、缓存、消息队列等
  • 收集应用程序的度量数据,例如内存使用情况、GC情况、线程状态等
  • 查看应用程序的配置信息,包括环境变量、系统属性、配置文件中的属性等
  • 管理应用程序的日志,包括查看和动态修改日志级别
  • 获取应用程序的 Spring Bean 信息,以及应用程序的元数据等
  • 提供应用程序的关闭功能等

2.2 内置端点详解

2.2.1 Actuator 端点说明

端点

描述

auditevents

获取当前应用暴露的审计事件信息

beans

获取应用中所有的 Spring Beans 的完整关系列表

caches

获取公开可以用的缓存

conditions

获取自动配置条件信息,记录哪些自动配置条件通过和没通过的原因

configprops

获取所有配置属性,包括默认配置,显示一个所有 @ConfigurationProperties 的整理列版本

env

获取所有环境变量

flyway

获取已应用的所有Flyway数据库迁移信息,需要一个或多个 Flyway Bean

liquibase

获取已应用的所有Liquibase数据库迁移。需要一个或多个 Liquibase Bean

health

获取应用程序健康指标(运行状况信息)

httptrace

获取HTTP跟踪信息(默认情况下,最近100个HTTP请求-响应交换)。需要 HttpTraceRepository Bean

info

获取应用程序信息

integrationgraph

显示 Spring Integration 图。需要依赖 spring-integration-core

loggers

显示和修改应用程序中日志的配置

logfile

返回日志文件的内容(如果已设置logging.file.name或logging.file.path属性)

metrics

获取系统度量指标信息

mappings

显示所有@RequestMapping路径的整理列表

scheduledtasks

显示应用程序中的计划任务

sessions

允许从Spring Session支持的会话存储中检索和删除用户会话。需要使用Spring Session的基于Servlet的Web应用程序

shutdown

关闭应用,要求endpoints.shutdown.enabled设置为true,默认为 false

threaddump

获取系统线程转储信息

heapdump

返回hprof堆转储文件

jolokia

通过HTTP公开JMX bean(当Jolokia在类路径上时,不适用于WebFlux)。需要依赖 jolokia-core

prometheus

以Prometheus服务器可以抓取的格式公开指标。需要依赖 micrometer-registry-prometheus

2.2.2 常用端点详解

(1)health

主要用来检测应用的运行状况,是使用最多的一个监控点。监控软件通常使用该接口实时监测应用运行状况,在系统出现故障时把报警信息推送给相关人员,如磁盘空间使用情况、数据库和缓存等的一些健康指标。 默认情况下 health 端点是开放的,访问 http://127.0.0.1:8080/actuator/health 即可看到应用运行状态。

{"status":"UP"}

如果需要看到详细信息,则需要做添加配置:

management.endpoint.health.show-details=always

访问返回信息如下:

{"status":"UP","details":{"diskSpace":{"status":"UP","details":{"total":180002725888,"free":8687988736,"threshold":10485760}}}}

(2)info

查看应用信息是否在 application.properties 中配置。如我们在项目中配置是:

info.app.name=Spring Boot Actuator Demo
info.app.version=v1.0.0
info.app.description=Spring Boot Actuator Demo

启动项目,访问 http://127.0.0.1:8080/actuator/info 返回信息如下:

{"app":{"name":"Spring Boot Actuator Demo","version":"v1.0.0","description":"Spring Boot Actuator Demo"}}

(3)env

通过 env 可以获取到所有关于当前 Spring Boot 应用程序的运行环境信息,如:操作系统信息(systemProperties)、环境变量信息、JDK 版本及 ClassPath 信息、当前启用的配置文件(activeProfiles)、propertySources、应用程序配置信息(applicationConfig)等。

可以通过 http://127.0.0.1:8080/actuator/env/{name} ,name表示想要查看的信息,可以独立显示。

(4)beans

访问 http://127.0.0.1:8080/actuator/beans 返回部分信息如下:

{
    "contexts": {
        "Spring Boot Actuator Demo": {
            "beans": {
                "endpointCachingOperationInvokerAdvisor": {
                    "aliases": [
                    ],
                    "scope": "singleton",
                    "type": "org.springframework.boot.actuate.endpoint.invoker.cache.CachingOperationInvokerAdvisor",
                    "resource": "class path resource [org/springframework/boot/actuate/autoconfigure/endpoint/EndpointAutoConfiguration.class]",
                    "dependencies": [
                        "environment"
                    ]
                },
                "defaultServletHandlerMapping": {
                    "aliases": [
                    ],
                    "scope": "singleton",
                    "type": "org.springframework.web.servlet.HandlerMapping",
                    "resource": "class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]",
                    "dependencies": [
                    ]
                },
                ...
            }
        }
    }
}

从返回的信息中我们可以看出主要展示了 bean 的别名、类型、是否单例、类的地址、依赖等信息。

(5)conditions

通过 conditions 可以在应用运行时查看代码了某个配置在什么条件下生效,或者某个自动配置为什么没有生效。

访问 http://127.0.0.1:8080/actuator/conditions 返回部分信息如下:

{
    "contexts": {
        "Spring Boot Actuator Demo": {
            "positiveMatches": {
                "SpringBootAdminClientAutoConfiguration": [
                    {
                        "condition": "OnWebApplicationCondition",
                        "message": "@ConditionalOnWebApplication (required) found 'session' scope"
                    },
                    {
                        "condition": "SpringBootAdminClientEnabledCondition",
                        "message": "matched"
                    }
                ],
                "SpringBootAdminClientAutoConfiguration#metadataContributor": [
                    {
                        "condition": "OnBeanCondition",
                        "message": "@ConditionalOnMissingBean (types: de.codecentric.boot.admin.client.registration.metadata.CompositeMetadataContributor; SearchStrategy: all) did not find any beans"
                    }
                ],
                ...
            }
        }
    }
}

(6) loggers

获取系统的日志信息。

访问 http://127.0.0.1:8080/actuator/loggers 返回部分信息如下:

{
    "levels": [
        "OFF",
        "ERROR",
        "WARN",
        "INFO",
        "DEBUG",
        "TRACE"
    ],
    "loggers": {
        "ROOT": {
            "configuredLevel": "INFO",
            "effectiveLevel": "INFO"
        },
        "cn": {
            "configuredLevel": null,
            "effectiveLevel": "INFO"
        },
        "cn.zwqh": {
            "configuredLevel": null,
            "effectiveLevel": "INFO"
        },
        "cn.zwqh.springboot": {
            "configuredLevel": null,
            "effectiveLevel": "INFO"
        },
        ...
    }
}

(7)mappings

查看所有 URL 映射,即所有 @RequestMapping 路径的整理列表。

访问 http://127.0.0.1:8080/actuator/mappings 返回部分信息如下:

{
    "contexts": {
        "Spring Boot Actuator Demo": {
            "mappings": {
                "dispatcherServlets": {
                    "dispatcherServlet": [
                        {
                            "handler": "ResourceHttpRequestHandler [class path resource [META-INF/resources/], class path resource [resources/], class path resource [static/], class path resource [public/], ServletContext resource [/], class path resource []]",
                            "predicate": "/**/favicon.ico",
                            "details": null
                        },
                        ...
                    ]
                }
            }
        }
    }
}

(8)heapdump

访问:http://127.0.0.1:8080/actuator/heapdump会自动生成一个 GZip 压缩的 Jvm 的堆文件 heapdump,我们可以使用 JDK 自带的 Jvm 监控工具 VisualVM 打开此文件查看。如图:



VisualVM下载:https://visualvm.github.io/download.html

(9)threaddump

获取系统线程的转储信息,主要展示了线程名、线程ID、线程的状态、是否等待锁资源等信息。在工作中,我们可以通过查看线程的情况来排查相关问题。

访问 http://127.0.0.1:8080/actuator/threaddump 返回部分信息如下:

{
    "threads": [
        {
            "threadName": "DestroyJavaVM",
            "threadId": 40,
            "blockedTime": -1,
            "blockedCount": 0,
            "waitedTime": -1,
            "waitedCount": 0,
            "lockName": null,
            "lockOwnerId": -1,
            "lockOwnerName": null,
            "inNative": false,
            "suspended": false,
            "threadState": "RUNNABLE",
            "stackTrace": [
            ],
            "lockedMonitors": [
            ],
            "lockedSynchronizers": [
            ],
            "lockInfo": null
        },
        ...
    ]
}

(10)shutdown

开启可以接口关闭 Spring Boot 应用,要使用这个功能需要做如下配置:

management.endpoint.shutdown.enabled=true

可以通过 post(仅支持 post) 请求访问 http://127.0.0.1:8080/actuator/shutdown 关闭应用。

(11)metrics

访问 http://127.0.0.1:8080/actuator/metrics 可以获取系统度量指标信息项如下:

{
    "names": [
        "jvm.memory.max",
        "jvm.threads.states",
        "jvm.gc.pause",
        "http.server.requests",
        "process.files.max",
        "jvm.gc.memory.promoted",
        "system.load.average.1m",
        "jvm.memory.used",
        "jvm.gc.max.data.size",
        "jvm.memory.committed",
        "system.cpu.count",
        "logback.events",
        "tomcat.global.sent",
        "jvm.buffer.memory.used",
        "tomcat.sessions.created",
        "jvm.threads.daemon",
        "system.cpu.usage",
        "jvm.gc.memory.allocated",
        "tomcat.global.request.max",
        "tomcat.global.request",
        "tomcat.sessions.expired",
        "jvm.threads.live",
        "jvm.threads.peak",
        "tomcat.global.received",
        "process.uptime",
        "tomcat.sessions.rejected",
        "process.cpu.usage",
        "tomcat.threads.config.max",
        "jvm.classes.loaded",
        "jvm.classes.unloaded",
        "tomcat.global.error",
        "tomcat.sessions.active.current",
        "tomcat.sessions.alive.max",
        "jvm.gc.live.data.size",
        "tomcat.threads.current",
        "process.files.open",
        "jvm.buffer.count",
        "jvm.buffer.total.capacity",
        "tomcat.sessions.active.max",
        "tomcat.threads.busy",
        "process.start.time"
    ]
}

对应访问 names 中的指标,可以查看具体的指标信息。如访问 http://127.0.0.1:8080/actuator/metrics/jvm.memory.used 返回信息如下:

{
    "name": "jvm.memory.used",
    "description": "The amount of used memory",
    "baseUnit": "bytes",
    "measurements": [
        {
            "statistic": "VALUE",
            "value": 1.16828136E8
        }
    ],
    "availableTags": [
        {
            "tag": "area",
            "values": [
                "heap",
                "nonheap"
            ]
        },
        {
            "tag": "id",
            "values": [
                "Compressed Class Space",
                "PS Survivor Space",
                "PS Old Gen",
                "Metaspace",
                "PS Eden Space",
                "Code Cache"
            ]
        }
    ]
}

2.3 定制端点

2.3.1 修改端点 ID

每个 Actuator 端点都有一个ID用来决定端点的路径,比方说,/beans端点的默认ID就是beans

如果端点的路径是由ID决定的,那么可以通过修改ID来改变端点的路径。你要做的就是设置一个属性,属性名是endpoints.endpoint-id.id

我们用/shutdown端点来做个演示,它会响应发往/shutdownPOST请求。假设你想让它处理发往/kill的POST请求,可以通过如下YAML/shutdown赋予一个新的ID,也就是新的路径:

endpoints: 
 shutdown:
  id: kill

重命名端点、修改其路径的理由很多。最明显的理由就是,端点的命名要和团队的术语保持一致。你也可能想重命名端点,让那些熟悉默认名称的人找不到它,借此增加一些安全感。

遗憾的是,重命名端点并不能真的起到保护作用,顶多是让黑客慢点找到它们。现在先让我们来看看如何禁用某个(或全部)不希望别人访问的端点。

2.3.2 启用和禁用端点

虽然Actuator的端点都很有用,但你不一定需要全部这些端点。默认情况下,所有端点(除了/shutdown)都启用。这里就不详细介绍如何设置endpoints.shutdown.enabled为true,以此开启/shutdown端点。用同样的方式,你可以禁用其他的端点,将endpoints. endpoint-id.enabled设置为false。

例如,要禁用/metrics端点,你要做的就是将endpoints.metrics.enabled属性设置为false。在application.yml里做如下设置:

endpoints: 
 metrics: 
 enabled: false

如果你只想打开一两个端点,那就先禁用全部端点,然后启用那几个你要的,这样更方便。例如,考虑如下application.yml片段:

endpoints: 
 enabled: false 
 metrics: 
   enabled: true

正如以上片段所示,endpoints.enabled设置为false就能禁用Actuator的全部端点,然后将endpoints.metrics.enabled设置为true重新启用/metrics端点。

2.3.3 只开启所需端点

控制所有端点开关,可以在此之后进行单个的开操作: endpoints.enabled=false

endpoints: 
 enabled-by-default: false 
 metrics: 
   enabled: true
   # 开启了metrics端点

2.3.4 定制端点访问路径

修改端点访问路径: management.context-path=/manage

2.3.5 修改http端点端口

修改端点访问端口: management.port=8081 值为-1时关闭http端点

2.3.6 关闭http端点

management: 
  server: 
    port: -1

因为http端口的范围是:1~65535,因此-1是访问不了的。

2.4 自定义端点

自定义端点

自定义前置条件,在pom.xml引入

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

2.4.1 自定义health

当内置的health端点信息不满足用来判断我们项目是否健康时,我们可以自定义health

通过实现org.springframework.boot.actuate.health.HealthIndicator接口,形如

@Component
public class CustomHealthIndicator implements HealthIndicator {

    @Override
    public Health health() {
        int errorCode = check();
        if (errorCode == 1) {
            return Health.down().withDetail("Error Code", errorCode).build();
        }
        return Health.up().build();
    }

    private int check() {
        // perform some specific health check
        return ThreadLocalRandom.current().nextInt(5);
    }

}

或者通过继承org.springframework.boot.actuate.health.AbstractHealthIndicator,形如

@Component("otherCustom")
public class CustomAbstractHealthIndicator extends AbstractHealthIndicator {
    @Override
    protected void doHealthCheck(Health.Builder builder) throws Exception {

        int errorCode = check();
        if (errorCode == 1) {
            builder.down().down().withDetail("Error Code", errorCode).build();
            return;
        }
        builder.up().build();

    }

    private int check() {
        // perform some specific health check
        return ThreadLocalRandom.current().nextInt(5);
    }
}

推荐使用继承AbstractHealthIndicator 这种方式。在配置文件中作如下配置,可以查看详细的健康信息

management:
   endpoint:
      health:
        show-details: always

通过访问http://ip:port/actuator/health进行查看,形如下



从图片我们可以看出,我们自定义的health端点信息,如果@Component不指定name,形如CustomHealthIndicator ,默认是取custom作为自定义端点对象

2.4.2 自定义info

我们可以通过实现org.springframework.boot.actuate.info.InfoContributor接口,来暴露一些我们想展示的信息。形如

@Component
public class CustomInfoContributor implements InfoContributor {

    @Override
    public void contribute(Info.Builder builder) {
        builder.withDetail("customInfo", Collections.singletonMap("hello", "world"));
    }

}

通过访问http://ip:port/actuator/info进行查看,形如下



2.4.3 自定义endpoint

有时候我们需要自定义自己的端点,我们可以通过 @Endpoint注解 + @ReadOperation、@WriteOperation、@DeleteOperation注解来实现自定义端点。形如下

@Component
@Endpoint(id = "customEndpoint")
public class CustomEndpoint {

  // @ReadOperation 对应GET请求

  /**
   * 请求示例:
   * GET http://localhost:8080/actuator/customEndpoint/zhangsan/20
   * @param username
   * @param age
   *
   * @return
   */
  @ReadOperation
  public Map<String, Object> endpointByGet(@Selector String username,@Selector Integer age) {
    Map<String, Object> customMap = new HashMap<>();
    customMap.put("httpMethod", HttpMethod.GET.toString());
    customMap.put("username",username);
    customMap.put("age",age);
    return customMap;
  }


  // @WriteOperation 对应POST请求

  /**
   * 请求示例:
   * POST http://localhost:8080/actuator/customEndpoint
   *
   * 请求参数为json格式
   *
   * {
   * "username": "zhangsan",
   * "age": 20
   * }
   *
   * @param username 参数都为必填项
   * @param age 参数都为必填项
   * @return
   */
  @WriteOperation
  public Map<String, Object> endpointByPost(String username,Integer age) {
    Map<String, Object> customMap = new HashMap<>();
    customMap.put("httpMethod", HttpMethod.POST.toString());
    customMap.put("username",username);
    customMap.put("age",age);
    return customMap;
  }


  // @DeleteOperation 对应Delete请求

  /**
   * 请求示例:
   * DELETE http://localhost:8080/actuator/customEndpoint
   *
   * @return
   */
  @DeleteOperation
  public Map<String, Object> endpointByDelete() {
    Map<String, Object> customMap = new HashMap<>();
    customMap.put("httpMethod", HttpMethod.DELETE.toString());

    return customMap;
  }

代码片段里面有比较详细的注释,这边就不在论述。这边有个细节就是,我们需要在yml作如下配置来暴露我们自定义的端点

management:
  endpoints:
    web:
      exposure:
        include: customEndpoint

或者

management:
  endpoints:
    web:
      exposure:
        include: "*"

对通用的自定义端点,更详细的端点介绍可以查看官网,链接如下

https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator

3 JMX

3.1 开启JMX

1、Spring Boot < 2.2.X 默认是启用JMX(Java Management Extensions) 的,并且默认是公开的MBeans,可以直接使用jdk自带的jconsole(shell窗口使用命令jconsole即可)客户端查看Mbeans.

2、使用JMX,那么所有的Actuator端点(除了/heapdump)会通过MBeans进行公开的。

3、请注意 Spring Boot > 2.2.x 默认禁用 JMX 暴露,需要添加以下设置才能使其工作:

spring.jmx.enabled=true

在命令行中执行jconsole命令启动“Java管理和监视控制台”,然后选择org.springframework.boot节点下的Endpoint,可以看到如下信息:




4、请注意 Spring Boot > 2.2.x 默认禁用 JMX Tomcat Bean 暴露,需要添加以下设置才能使其工作:

server.tomcat.mbeanregistry.enabled=true

在命令行中执行jconsole命令启动“Java管理和监视控制台”,然后选择Tomcat,可以看到如下信息:




3.2 禁用JMX

如果不希望在JMX上公开端点,您可以设置management.endpoints.jmx.exposure.exclude属性为*,如下例所示:

management.endpoints.jmx.exposure.exclude=*

如果 Spring Boot > 2.2.x 默认禁用 JMX 暴露。

3.3 访问JMX

除了通过JMX获取信息,也可以通过HTTP接口访问Mbeans对象的信息,具体有以下两种方式。

  • actuator的metrics

部分指标会暴露在actuator的metrics下面,比如:tomcat thread的相关指标、jvm的相关指标、连接池(hikaricp等)的相关指标(具体暴露哪些指标,取决于配置情况)。

1、在应用的pom文件中添加jolokia-core依赖:

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

2、配置:

在application.properties文件:

# Actuator Web 访问端口
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always
management.server.port=10111
management.server.ssl.enabled=false
management.server.servlet.context-path=/
		
spring.jmx.enabled=true
server.tomcat.mbeanregistry.enabled=true
management.endpoints.jmx.exposure.include=*

3、测试验证:



4 SSH

Spring Boot支持集成一个称为'CRaSH'的Java shell,你可以在CRaSH中使用ssh或telnet命令连接到运行的应用,项目中添加以下依赖可以启用远程shell支持:

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

如果想使用telnet访问,你还需添加对org.crsh:crsh.shell.telnet的依赖。

CRaSH运行时需要JDK,因为它要动态编译命令。如果一个基本的help命令都运行失败,你很可能使用的是JRE。

配置用户名及密码

#设置用户名
management.shell.auth.simple.user.name=xxx  
#设置密码
management.shell.auth.simple.user.password=xxx

4.1 连接远程shell

远程shell默认监听端口为2000,默认用户名为user,密码为随机生成的,并且在输出日志中会显示。如果应用使用Spring Security,该shell默认使用相同的配置。如果不是,将使用一个简单的认证策略,你可能会看到类似这样的信息:

Using default password for shell access: ec03e16c-4cf4-49ee-b745-7c8255c1dd7e

或者在配置文件中设置用户名和密码。

Linux和OSX用户可以使用ssh连接远程shell,Windows用户可以下载并安装PuTTY。

$ ssh -p 2000 user@localhost

user@localhost's password:
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::  (v1.4.1.RELEASE) on myhost

输入help可以获取命令列表,Spring Boot提供metricsbeansautoconfigendpoint命令。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表