说明

Spring Boot Actuatorspring boot项目一个监控模块,提供了很多原生的端点,包含了对应用系统的自身和监控的集成功能,可以查看应用配置的详细信息,比如应用程序上下文里全部的Bean健康指标环境变量各类重要度量指标等等,这些都是使用可HTTP进行请求访问。通过这些监控信息,我们就能随时了解应用的运行情况了。

执行端点

Spring Boot 提供了很多执行器端点(endpoints)用于监控应用的运行情况以及与应用进行交互,并支持将这些端点按需暴露给外部使用。 端点暴露的方式取决于你采用的技术类型,通常可以端点的 ID 映射到一个 URL,从而可以将端口暴露为 HTTP 服务。例如,将health 端点默认映射到 /health。Spring Boot 内置的常用端点如下:

ID 描述 是否敏感
actuator 为其他端点提供基于超文本的导航页面,需要添加 Spring HATEOAS 依赖 true
autoconfig 显示一个自动配置类的报告,该报告展示所有自动配置候选者及它们被应用或未被应用的原因 true
beans 显示一个应用中所有 Spring Beans 的完整列表 true
configprops 显示一个所有 @ConfigurationProperties 的集合列表 true
dump 执行一个线程转储 true
env 暴露来自 Spring ConfigurableEnvironment 的属性 true
flyway 显示数据库迁移路径,如果有的话 true
health 展示应用的健康信息(当使用一个未认证连接访问时显示一个简单的 ‘status’,使用认证连接访问则显示全部信息详情) false
info 显示任意的应用信息 false
liquibase 展示任何 Liquibase 数据库迁移路径,如果有的话 true
metrics 展示当前应用的 ‘metrics’ 信息 true
mappings 显示一个所有 @RequestMapping 路径的集合列表 true
shutdown 允许应用以优雅的方式关闭(默认情况下不启用) true
trace 显示 trace 信息(默认为最新的 100 条 HTTP 请求) true

如果使用了 Spring MVC,还有以下额外的端点:

ID 描述 是否敏感
docs 展示 Actuator 的文档,包括示例请求和响应,需添加 spring-boot-actuator-docs 依赖 false
heapdump 返回一个 GZip 压缩的 hprof 堆转储文件 true
jolokia 通过 HTTP 暴露 JMX beans(依赖 Jolokia) true
logfile 返回日志文件内容(如果设置 logging.file 或 logging.path 属性),支持使用 HTTP Range 头接收日志文件内容的部分信息

端点按照安全属性可以分为敏感和非敏感两类,在启用 Web 安全服务后,访问敏感端点时需要提供用户名和密码,如果没有启用 web 安全服务,Spring Boot 可能会直接禁止访问该端点。

启用端点

默认情况下,除了 shutdown 以外的所有端点都已启用。端点的启停可以使用 management.endpoint.<id>.enabled 属性来进行控制,示例如下:

1
management.endpoint.shutdown.enabled = true

暴露端点

由于端点可能包含敏感信息,因此应仔细考虑后再决定是否公开。下表显示了内置端点的默认公开情况:

ID JMX Web
auditevents 没有
beans 没有
conditions 没有
configprops 没有
env 没有
flyway 没有
health
heapdump N / A 没有
httptrace 没有
info
jolokia N / A 没有
logfile N / A 没有
loggers 没有
liquibase 没有
metrics 没有
mappings 没有
prometheus N / A 没有
scheduledtasks 没有
sessions 没有
shutdown 没有
threaddump 没有

可以选择是否暴露端点(include)或者排除端点(exclude),其中排除属性优先于暴露属性:

属性 默认
management.endpoints.jmx.exposure.exclude
management.endpoints.jmx.exposure.include *
management.endpoints.web.exposure.exclude
management.endpoints.web.exposure.include info, health

健康检查

health 端点用于暴露程序运行的健康状态,暴露的信息的详细程度由 management.endpoint.health.show-details 来控制,它具有以下三个可选值:

名称 描述
never 细节永远不会显示。
when-authorized 详细信息仅向授权用户显示。授权角色可以使用配置 management.endpoint.health.roles。
always 详细信息显示给所有用户。

actuator API 接口说明

类型 API 接口 描述
GET /autoconfig 提供了一份自动配置报告,记录哪些自动配置条件通过了,哪些没有通过
GET /configprops 描述配置属性如何注入Bean
GET /beans 描述应用程序上下文里全部的Bean,以及他们的关系
GET /dump 获取线程活动的快照
GET /env 获取全部环境属性
GET /env/{name} 根据名称获取特定的环境属性值
GET /health 应用程序的健康指标
GET /info 获取应用程序的信息
GET /mappings 描述全部URL路径,及它们和控制器(包括Actuator端点)的映射关系
GET /metrics 获取应用程序度量信息,比如内存用量和http请求计算
GET /metrics/{name} 获取程序指定名称的度量信息
GET /shutdown 关闭应用程序,要求endpoints.shutdown.enabled设值为true
GET /trace 提供基本的HTTP请求跟踪信息(时间戳,HTTP头)等

项目设置

依赖pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

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

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

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

配置文件 application.yaml

  • springboot 1.5x 版本默认开启了 Actuator 的安全验证,要做安全验证

  • 使用的是SpringBoot2.x的版本,其和1.x版本是有区别的,需要额外开启端点,默认只开启了info、health两个端点,其他的需要额外去配置的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    server:
    port: 8080
    servlet:
    context-path: /demo
    # 若要访问端点信息,需要配置用户名和密码
    spring:
    security:
    user:
    name: fulsun
    password: 123456
    management:
    # 端点信息接口使用的端口,为了和主系统接口使用的端口进行分离
    server:
    port: 8090
    servlet:
    context-path: /sys
    # 端点健康情况,默认值"never",设置为"always"可以显示硬盘使用情况和线程情况
    endpoint:
    health:
    show-details: always
    # 设置端点暴露的哪些内容,默认["health","info"],设置"*"代表暴露所有可访问的端点
    endpoints:
    web:
    exposure:
    include: "*"

监控状态

自定义健康检查指标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@JsonInclude(Include.NON_EMPTY)
public final class Status {

/**
* {@link Status} indicating that the component or subsystem is in an unknown state.
*/
public static final Status UNKNOWN = new Status("UNKNOWN");

/**
* {@link Status} indicating that the component or subsystem is functioning as
* expected.
*/
public static final Status UP = new Status("UP");

/**
* {@link Status} indicating that the component or subsystem has suffered an
* unexpected failure.
*/
public static final Status DOWN = new Status("DOWN");

/**
* {@link Status} indicating that the component or subsystem has been taken out of
* service and should not be used.
*/
public static final Status OUT_OF_SERVICE = new Status("OUT_OF_SERVICE");

health的Status枚举

  • 代码如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    package tk.fulsun.demo.indicator;

    import org.springframework.boot.actuate.health.Health;
    import org.springframework.boot.actuate.health.HealthIndicator;
    import org.springframework.stereotype.Component;

    /**
    * @Description 自定义健康检查指标
    * @Date 2021/6/23
    * @Created by 凉月-文
    */
    @Component(value = "CPUHealth")
    public class CustomHealthIndicator implements HealthIndicator {

    @Override
    public Health health() {
    double random = Math.random();
    // 这里用随机数模拟健康检查的结果
    if (random > 0.5) {
    return Health.status("FATAL").withDetail("error code", "CPU转疯了").build();
    } else {
    return Health.up().withDetail("success code", "CPU检查一切正常").build();
    }

    }
    }

  • 自定义检查通过的情况下:

  • 自定义检查失败的情况:

    自定义检查不论是否通过都不会影响整体的 status,因此两种情况下的 status 值都是 up。如果想通过自定义检查去影响整体的检查结果,比如健康检查针对的是支付业务,在支付业务的不可用的情况下,我们就应该认为整个服务是不可用的,这个时候就需要通过自定义健康状态的聚合规则来实现。

定义健康状态的聚合规则

  • 对于多个HealthIndicator的status,spring boot默认对其进行aggregrate,然后计算最顶层的status字段的值,而且对于status是DOWN或者是OUT_OF_SERVICE的,返回的http的状态码是503

  • AbstractHealthAggregator.java的抽象类,其中对状态的聚合是abstract的。

  • 自定义代码如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    package tk.fulsun.demo.aggregator;

    import org.springframework.boot.actuate.health.Health;
    import org.springframework.boot.actuate.health.HealthAggregator;
    import org.springframework.stereotype.Component;

    import java.util.Map;

    /**
    * @Description 对所有的自定义健康指标进行聚合,按照自定义规则返回总和健康状态
    * @Date 2021/6/23
    * @Created by 凉月-文
    */
    @Component
    public class CustomHealthAggregator implements HealthAggregator {

    @Override
    public Health aggregate(Map<String, Health> healths) {
    for (Health health : healths.values()) {
    // 聚合规则可以自定义,这里假设我们自定义的监控状态中有一项FATAL,就认为整个服务都是不可用的,否则认为整个服务是可用的
    if (health.getStatus().getCode().equals("FATAL")) {
    return Health.status("FATAL").withDetail("error code", "综合判断后服务宕机").build();
    }
    }
    return Health.up().build();
    }
    }
  • HealthAggregator在2.2之后被废弃

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    package tk.fulsun.demo.aggregator;

    import org.springframework.boot.actuate.health.Status;
    import org.springframework.boot.actuate.health.StatusAggregator;
    import org.springframework.stereotype.Component;

    import java.util.Set;

    /**
    * @Description 对所有的自定义健康指标进行聚合,按照自定义规则返回总和健康状态
    * @Date 2021/6/23
    * @Created by 凉月-文
    */
    @Component
    public class CustomHealthAggregator implements StatusAggregator {

    @Override
    public Status getAggregateStatus(Set<Status> statuses) {
    statuses.stream().forEach(System.out::println);
    if (statuses.contains(new Status("FATAL"))) {
    return Status.DOWN; // DOWN状态默认返回503状态码
    }
    return Status.UP;
    }
    }
  • 当我们自定义健康检查项不通过时候的结果如下:

修改状态码503

  • 503 Service Unavailable:抱歉,我现在正在忙着。

  • 该状态码表明服务器暂时处于超负载或正在停机维护,现在无法处理请求。

  • 在配置文件中进行定义的:

    1
    management.health.status.http-mapping.FATAL = 503
  • 失败情况

  • 成功

内置状态的默认映射:

  • 内置状态如下:

    Status Mapping
    DOWN SERVICE_UNAVAILABLE (503)
    OUT_OF_SERVICE SERVICE_UNAVAILABLE (503)
    UP No mapping by default, so http status is 200
    UNKNOWN No mapping by default, so http status is 200
  • 我们可以直接返回DOWN,不用自己定义的FATAL