Spring Boot 教程7:Actuator

Spring Boot 教程7:Actuator

声明

这个系列文章是翻译自https://www.baeldung.com/的系列博客,个人感觉是一个非常不错的Spring Boot 教程。原网站属于一个公司,主要开展有偿培训业务,但提供相关文字教程的免费阅读和下载。因为我并没有在网页找到相关版权描述信息,所以并不能确定是否可以自由翻译和转载,如果有版权问题,请联系我,我会撤下这个系列文章。

原文地址:Spring Boot Actuator | Baeldung

因为版权的关系,本文禁止转载。


概述

在这篇文章中,我们将介绍Spring Boot Actuator。我们将首先介绍基础知识,然后详细讨论Spring Boot 2.x与1.x中的可用性。

我们将学习如何在Spring Boot 2.x和WebFlux中使用、配置和扩展这个监控工具,利用响应式编程模型。然后,我们将讨论如何使用Boot 1.x执行相同的操作。

随着Spring Boot 2的发布,,执行器已经重新设计,并添加了新的令人兴奋的端点。

我们将本指南分为三个主要部分:

  • 什么是Actuator?
  • Spring Boot 2.x Actuator
  • Spring Boot 1.x Actuator

什么是 Actuator ?

从本质上讲,致动器(Actuator)为我们的应用程序带来了生产就绪功能。

监控我们的应用程序、收集指标、了解流量或数据库状态都变得微不足道。

这个库的主要好处是,我们可以获得生产级工具,而不必自己实际实现这些功能。

Actuator主要用于公开正在运行的应用程序的操作信息——健康、指标、信息、转储、环境等。它使用HTTP端点或JMXbean使我们能够与之交互。

一旦这个依赖项位于类路径上,我们就可以使用几个现成的端点。与大多数Spring模块一样,我们可以通过多种方式轻松地配置或扩展它。

开始使用

要启用Spring Boot Actuator,我们只需要将spring-boot-actuator依赖项添加到我们的包管理器。

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

请注意,无论Boot版本如何,该选项都有效,因为版本在Spring Boot BOM表中指定。

Spring Boot 2.x Actuator

在2.x中,Actuator保留了其基本意图,但简化了模型,扩展了功能,并引入了更好的默认值。

首先,这个版本变得与技术无关。它还通过将其与应用程序合并来简化其安全模型。

在各种变化中,重要的是要记住,其中一些正在打破。这包括HTTP请求和响应以及Java API。

最后,最新版本现在支持CRUD模型,而不是旧的读/写模型。

技术支持

在第二个主要版本中,Actuator现在是技术不可知的,而在1.x中,它与MVC绑定,因此与Servlet API绑定。

在2.x中,Actuator将其模型定义为可插入和可扩展的,而不依赖于MVC。

因此,通过这个新模型,我们能够利用MVC和WebFlux作为底层Web技术。

此外,可以通过实施正确的适配器来添加即将到来的技术。

最后,JMX仍然支持公开端点,而不需要任何额外的代码。

重要变更

与以前的版本不同,Actuator禁用了大多数端点。

因此,默认情况下只有两个可用的是*/health/info*。

如果我们想启用所有这些,我们可以设置management.endpoints.web.exposure.include=*。或者,我们可以列出应该启用的端点。

Actuator现在与常规应用程序安全规则共享安全配置,因此安全模型得到了极大的简化。

因此,要调整Actuator安全规则,我们只需添加一个条目*/actuator/***:

@Bean
public SecurityWebFilterChain securityWebFilterChain(
  ServerHttpSecurity http) {
    return http.authorizeExchange()
      .pathMatchers("/actuator/**").permitAll()
      .anyExchange().authenticated()
      .and().build();
}

我们可以在全新的执行器官方文档上找到更多细节。

此外,默认情况下,所有Actuator端点现在都放置在*/actuator*路径下。

与上一个版本相同,我们可以使用新的属性 management.endpoints.web.base-path 来调整这个路径。

预定义端点

让我们来看看一些可用的端点(endpoint),其中大部分在1.x中已经可用。

此外,还添加了一些端点,删除了一些端点,并对一些端点进行了重组:

  • /auditevents 列出与安全审核相关的事件,例如用户登录/注销。此外,我们还可以按主体或类型过滤其他字段。
  • /beans 返回 BeanFactory 中所有可用的bean。与 /auditevents 不同,它不支持过滤。
  • /conditions, (以前称为 /autoconfig)构建有关自动配置的条件报告。
  • /configprops 允许我们获取所有 @ConfigurationProperties bean。
  • /env 返回当前环境属性。此外,我们可以检索单个属性。
  • /flyway 提供了有关Flyway数据库迁移的详细信息。
  • /health 总结了应用程序的运行状况。
  • /heapdump 从应用程序使用的JVM构建并返回堆转储。
  • /info 返回常规信息。它可能是自定义数据、构建信息或有关最新提交的详细信息。
  • /liquibase 的行为类似于 /flyway,但用于Liquibase。
  • /logfile 返回普通应用程序日志。
  • /loggers 使我们能够查询和修改应用程序的日志记录级别。
  • /metrics 详细说明了我们应用程序的指标。这可能包括通用指标以及自定义指标。
  • /prometheus 返回与前一个类似的指标,但格式设置为与Prometheus服务器一起使用。
  • /scheduledtasks 提供了应用程序中每个计划任务的详细信息。
  • /sessions 列出了我们使用Spring Session时的HTTP会话。
  • /shutdown 执行应用程序的正常关闭。
  • /threaddump 转储底层JVM的线程信息。

致动器端点的超媒体

Spring Boot 添加了一个发现端点,该端点返回所有可用执行器端点的链接。这将有助于发现执行器端点及其对应的URL。

默认情况下,可以通过/actuator端点访问此发现端点。

因此,如果我们向这个URL发送GET请求,它将返回各个端点的执行器链接:

{
  "_links": {
    "self": {
      "href": "http://localhost:8080/actuator",
      "templated": false
    },
    "features-arg0": {
      "href": "http://localhost:8080/actuator/features/{arg0}",
      "templated": true
    },
    "features": {
      "href": "http://localhost:8080/actuator/features",
      "templated": false
    },
    "beans": {
      "href": "http://localhost:8080/actuator/beans",
      "templated": false
    },
    "caches-cache": {
      "href": "http://localhost:8080/actuator/caches/{cache}",
      "templated": true
    },
    // truncated
}

如上所示,/actuator 端点在 _links 字段下报告所有可用的执行器端点。

此外,如果我们配置了自定义管理基本路径,那么我们应该使用该基本路径作为发现URL。

例如,如果我们将 management.endpoints.web.base-path 设置为 /mgmt,那么我们应该向 /mgmt 端点发送一个请求以查看链接列表。

非常有趣的是,当管理基本路径设置为/时,发现端点被禁用,以防止与其他映射冲突的可能性。

健康指标

就像在以前的版本中一样,我们可以轻松添加自定义指标。与其他API相反,用于创建自定义健康端点的抽象保持不变。但是,添加了一个新的接口 ReactiveHealthIndicator ,以实现响应式健康检查。

让我们来看看一个简单的自定义响应式健康检查:

@Component
public class DownstreamServiceHealthIndicator implements ReactiveHealthIndicator {

    @Override
    public Mono<Health> health() {
        return checkDownstreamServiceHealth().onErrorResume(
          ex -> Mono.just(new Health.Builder().down(ex).build())
        );
    }

    private Mono<Health> checkDownstreamServiceHealth() {
        // we could use WebClient to check health reactively
        return Mono.just(new Health.Builder().up().build());
    }
}

健康指标的一个方便特性是,我们可以将它们作为层次结构的一部分进行汇总。

因此,按照前面的示例,我们可以将所有下游服务分组到一个下游服务类别下。只要每个嵌套的服务都是可访问的,这个类别就是健康的。

查看我们关于健康指标的文章,以获得更深入的了解。

健康组

从Spring Boot 2.2开始,我们可以将健康指标组织到组中,并将相同的配置应用于所有组成员。

例如,我们可以通过将其添加到 application.properties 来创建名为 custom 的健康组:

management.endpoint.health.group.custom.include=diskSpace,ping

这样,自定义组包含 diskSpaceping 运行状况指示器。

现在,如果我们调用 /actuator/health 端点,它会在JSON响应中告诉我们新的健康组:

{"status":"UP","groups":["custom"]}

在健康组中,我们可以看到一些健康指标的汇总结果。

在这种情况下,如果我们向 /actuator/health/custom 发送请求,则:

{"status":"UP"}

我们可以通过 application.properties 配置组以显示更多详细信息:

management.endpoint.health.group.custom.show-components=always
management.endpoint.health.group.custom.show-details=always

现在,如果我们将相同的请求发送到 /actuator/health/custom,我们将看到更多的细节:

{
  "status": "UP",
  "components": {
    "diskSpace": {
      "status": "UP",
      "details": {
        "total": 499963170816,
        "free": 91300069376,
        "threshold": 10485760
      }
    },
    "ping": {
      "status": "UP"
    }
  }
}

也可以仅为授权用户显示这些详细信息:

management.endpoint.health.group.custom.show-components=when_authorized
management.endpoint.health.group.custom.show-details=when_authorized

我们也可以有一个自定义的状态映射。

例如,它可以返回207状态码,而不是HTTP 200 OK响应:

management.endpoint.health.group.custom.status.http-mapping.up=207

在这里,我们告诉 Spring Boot 如果自定义组状态为UP,则返回207 HTTP状态代码。

在Spring Boot 2.0中,内部指标被Micrometer支持所取代,因此我们可以期待突破性的变化。如果我们的应用程序使用度量服务,如GaugeService或CounterService,它们将不再可用。

相反,我们希望直接与Micrometer交互。在Spring Boot 2.0中,我们将获取到一个为我们自动配置的 MeterRegistry 类型的bean。

此外,Micrometer现在是Actuator的依赖项的一部分,所以只要Actuator依赖项在类路径中,一切就都很好。

此外,我们将从 /metrics 端点获得一个全新的响应:

{
  "names": [
    "jvm.gc.pause",
    "jvm.buffer.memory.used",
    "jvm.memory.used",
    "jvm.buffer.count",
    // ...
  ]
}

正如我们所看到的,没有我们在1.x中得到的实际指标。

为了获得特定度量的实际值,我们现在可以导航到期望的度量,例如,/actuator/metrics/jvm.gc.pause,并获得详细的响应:

{
  "name": "jvm.gc.pause",
  "measurements": [
    {
      "statistic": "Count",
      "value": 3.0
    },
    {
      "statistic": "TotalTime",
      "value": 7.9E7
    },
    {
      "statistic": "Max",
      "value": 7.9E7
    }
  ],
  "availableTags": [
    {
      "tag": "cause",
      "values": [
        "Metadata GC Threshold",
        "Allocation Failure"
      ]
    },
    {
      "tag": "action",
      "values": [
        "end of minor GC",
        "end of major GC"
      ]
    }
  ]
}

现在的度量标准更加全面,不仅包括不同的值,还包括一些相关的元数据。

自定义/info端点

/info 端点保持不变。和前面一样,我们可以使用相应的Maven或Gradle依赖项添加git细节:

<dependency>
    <groupId>pl.project13.maven</groupId>
    <artifactId>git-commit-id-plugin</artifactId>
</dependency>

同样,我们还可以使用Maven或Gradle插件包括构建信息,包括名称,组和版本:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <executions>
        <execution>
            <goals>
                <goal>build-info</goal>
            </goals>
        </execution>
    </executions>
</plugin>

创建自定义端点

正如我们之前指出的,我们可以创建自定义端点。然而,Spring Boot 2重新设计了实现这一目标的方式,以支持新的技术不可知范式。

让我们创建一个Actuator端点来查询、启用和禁用应用程序中的功能标志:

@Component
@Endpoint(id = "features")
public class FeaturesEndpoint {

    private Map<String, Feature> features = new ConcurrentHashMap<>();

    @ReadOperation
    public Map<String, Feature> features() {
        return features;
    }

    @ReadOperation
    public Feature feature(@Selector String name) {
        return features.get(name);
    }

    @WriteOperation
    public void configureFeature(@Selector String name, Feature feature) {
        features.put(name, feature);
    }

    @DeleteOperation
    public void deleteFeature(@Selector String name) {
        features.remove(name);
    }

    public static class Feature {
        private Boolean enabled;

        // [...] getters and setters 
    }

}

要获得端点,我们需要一个bean。在我们的示例中,我们使用 @Component 来实现此目的。另外,我们需要用 @Endpoint 装饰这个bean。

我们的端点的路径由 @Endpointid 参数决定。在我们的例子中,它将请求路由到 /actuator/features

一旦准备就绪,我们就可以开始使用以下命令定义操作:

  • @ReadOperation :它将映射到HTTP GET。
  • @WriteOperation :它将映射到HTTP POST。
  • @DeleteOperation :它将映射到HTTP DELETE。

当我们在应用程序中使用前一个端点运行应用程序时,Spring Boot 将注册它。

验证这一点的一个快速方法是检查日志:

[...].WebFluxEndpointHandlerMapping: Mapped "{[/actuator/features/{name}],
  methods=[GET],
  produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
[...].WebFluxEndpointHandlerMapping : Mapped "{[/actuator/features],
  methods=[GET],
  produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
[...].WebFluxEndpointHandlerMapping : Mapped "{[/actuator/features/{name}],
  methods=[POST],
  consumes=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
[...].WebFluxEndpointHandlerMapping : Mapped "{[/actuator/features/{name}],
  methods=[DELETE]}"[...]

在前面的日志中,我们可以看到WebFlux是如何公开我们的新端点的。如果我们切换到MVC,它将简单地委托该技术,而无需更改任何代码。

此外,对于这种新方法,我们需要记住几个重要的注意事项:

  • 没有MVC的依赖关系。
  • 以前作为方法存在的所有元数据(敏感的,启用的…)都不再存在。但是,我们可以使用 *@Endpoint(id =“features”,enableByDefault = false)*启用或禁用端点。
  • 与1.x不同的是,不再需要扩展给定的接口。
  • 与旧的读/写模型相比,我们现在可以使用 @DeleteOperation 定义DELETE操作。

扩展现有端点

让我们想象一下,我们希望确保应用程序的生产实例永远不是SNAPSHOT版本。

我们决定通过更改返回此信息的Actuator端点的HTTP状态代码来实现此目的,即,/info.如果我们的应用碰巧是一个SNAPSHOT,我们将获得不同的HTTP状态代码。

我们可以使用 @EndpointExtension 注解或其更具体的专业化 @EndpointWebExtension@EndpointJmxExtension 轻松扩展预定义端点的行为:

@Component
@EndpointWebExtension(endpoint = InfoEndpoint.class)
public class InfoWebEndpointExtension {

    private InfoEndpoint delegate;

    // standard constructor

    @ReadOperation
    public WebEndpointResponse<Map> info() {
        Map<String, Object> info = this.delegate.info();
        Integer status = getStatus(info);
        return new WebEndpointResponse<>(info, status);
    }

    private Integer getStatus(Map<String, Object> info) {
        // return 5xx if this is a snapshot
        return 200;
    }
}

启用所有端点

为了使用HTTP访问执行器端点,我们需要启用并公开它们。

默认情况下,除 /shutdown 之外的所有端点都处于启用状态。默认情况下,仅公开 /health/info 端点。

我们需要添加以下配置来公开所有端点:

management.endpoints.web.exposure.include=*

要显式启用特定端点(例如,/shutdown),我们用:

management.endpoint.shutdown.enabled=true

要公开除一个端点(例如,/loggers),我们用:

management.endpoints.web.exposure.include=*
management.endpoints.web.exposure.exclude=loggers

Spring Boot 1.x Actuator

在1.x中,Actuator遵循读/写模型,这意味着我们可以从中读取或写入。

例如,我们可以检索应用程序的指标或健康状况。或者,我们可以优雅地终止应用程序或更改日志记录配置。

为了让它工作,Actuator需要Spring MVC通过HTTP公开其端点。不支持其他技术。

端点

在1.x中,Actuator带来了自己的安全模型。它利用了Spring Security构造,但需要独立于应用程序的其余部分进行配置。

此外,大多数端点都是敏感的——这意味着它们不是完全公开的,或者大多数信息将被省略-而少数端点不是,例如,/info.

以下是 Boot 提供的一些最常见的开箱即用端点:

  • /health 显示应用程序运行状况信息(通过未经身份验证的连接访问时的简单状态或通过身份验证时的完整消息详细信息);默认情况下不敏感。
  • /info 显示任意应用程序信息;默认情况下不敏感。
  • /metrics 显示当前应用程序的度量信息;默认情况下是敏感的
  • /trace 显示跟踪信息(默认情况下为最后几个HTTP请求)。

我们可以在官方文档中找到现有端点的完整列表。

配置现有端点

我们可以使用endpoints格式自定义每个端点的属性。[端点名称]。[要自定义的属性]。

有三个属性可用:

  • id:通过HTTP访问此端点的ID
  • enabled:如果为true,则可以访问;否则不
  • sensitive:如果为true,则需要授权才能通过HTTP显示关键信息

例如,添加以下属性将自定义 /beans 端点:

endpoints.beans.id=springbeans
endpoints.beans.sensitive=false
endpoints.beans.enabled=true

/health端点

/health 端点用于检查正在运行的应用程序的运行状况或状态。

它通常由监控软件执行,如果运行的实例因其他原因而停机或变得不健康,则会提醒我们,例如,数据库的连接问题、磁盘空间不足等。

默认情况下,未经授权的用户只能在通过HTTP访问时看到状态信息:

{
    "status" : "UP"
}

这些健康信息是从实现在我们的应用程序上下文中配置的HealthIndicator接口的所有bean中收集的。

HealthIndicator 返回的一些信息本质上是敏感的,但我们可以配置 endpoints.health.sensitive=false 来公开更详细的信息,如磁盘空间,消息传递代理连接,自定义检查等。

请注意,这仅适用于1.5.0以下的Spring Boot 版本。对于1.5.0和更高版本,我们还应该通过设置management.security.enabled=false来禁用安全性,以防止未经授权的访问。

我们还可以实现自己的自定义健康指示器,它可以收集特定于应用程序的任何类型的自定义健康数据,并通过 /health 端点自动公开它:

@Component("myHealthCheck")
public class HealthCheck implements HealthIndicator {
 
    @Override
    public Health health() {
        int errorCode = check(); // perform some specific health check
        if (errorCode != 0) {
            return Health.down()
              .withDetail("Error Code", errorCode).build();
        }
        return Health.up().build();
    }
    
    public int check() {
    	// Our logic to check health
    	return 0;
    }
}

输出如下所示:

{
    "status" : "DOWN",
    "myHealthCheck" : {
        "status" : "DOWN",
        "Error Code" : 1
     },
     "diskSpace" : {
         "status" : "UP",
         "free" : 209047318528,
         "threshold" : 10485760
     }
}

/info端点

我们还可以自定义 /info 端点显示的数据:

info.app.name=Spring Sample Application
info.app.description=This is my first spring boot application
info.app.version=1.0.0

以及示例输出:

{
    "app" : {
        "version" : "1.0.0",
        "description" : "This is my first spring boot application",
        "name" : "Spring Sample Application"
    }
}

/metrics 端点

度量端点发布有关OS和JVM以及应用程序级度量的信息。一旦启用,我们就可以获得内存、堆、处理器、线程、已加载类、已卸载类和线程池等信息,沿着一些HTTP指标。

以下是此端点的输出外观:

{
    "mem" : 193024,
    "mem.free" : 87693,
    "processors" : 4,
    "instance.uptime" : 305027,
    "uptime" : 307077,
    "systemload.average" : 0.11,
    "heap.committed" : 193024,
    "heap.init" : 124928,
    "heap.used" : 105330,
    "heap" : 1764352,
    "threads.peak" : 22,
    "threads.daemon" : 19,
    "threads" : 22,
    "classes" : 5819,
    "classes.loaded" : 5819,
    "classes.unloaded" : 0,
    "gc.ps_scavenge.count" : 7,
    "gc.ps_scavenge.time" : 54,
    "gc.ps_marksweep.count" : 1,
    "gc.ps_marksweep.time" : 44,
    "httpsessions.max" : -1,
    "httpsessions.active" : 0,
    "counter.status.200.root" : 1,
    "gauge.response.root" : 37.0
}

为了收集自定义指标,我们支持计量器(数据的单值快照)和计数器,即递增/递减度量。

让我们在/metrics端点中实现我们自己的定制度量。

我们将自定义登录流程以记录成功和失败的登录尝试:

@Service
public class LoginServiceImpl {

    private final CounterService counterService;
    
    public LoginServiceImpl(CounterService counterService) {
        this.counterService = counterService;
    }
	
    public boolean login(String userName, char[] password) {
        boolean success;
        if (userName.equals("admin") && "secret".toCharArray().equals(password)) {
            counterService.increment("counter.login.success");
            success = true;
        }
        else {
            counterService.increment("counter.login.failure");
            success = false;
        }
        return success;
    }
}

下面是输出可能的样子:

{
    ...
    "counter.login.success" : 105,
    "counter.login.failure" : 12,
    ...
}

请注意,登录尝试和其他与安全相关的事件在Actuator中作为审计事件开箱即用。

创建新端点

除了使用 Spring Boot 提供的现有端点之外,我们还可以创建一个全新的端点。

首先,我们需要让新的端点实现Endpoint接口:

@Component
public class CustomEndpoint implements Endpoint<List<String>> {
    
    @Override
    public String getId() {
        return "customEndpoint";
    }

    @Override
    public boolean isEnabled() {
        return true;
    }

    @Override
    public boolean isSensitive() {
        return true;
    }

    @Override
    public List<String> invoke() {
        // Custom logic to build the output
        List<String> messages = new ArrayList<String>();
        messages.add("This is message 1");
        messages.add("This is message 2");
        return messages;
    }
}

为了访问这个新端点,使用它的id来映射它。换句话说,我们可以通过点击 /customEndpoint 来练习它。

[ "This is message 1", "This is message 2" ]

进一步定制

出于安全考虑,我们可以选择通过非标准端口公开执行器端点—— management.port 属性可以轻松地用于配置。

如前所述,在1.x中。Actuator基于Spring Security配置自己的安全模型,但独立于应用程序的其余部分。

因此,我们可以更改 management.address 属性来限制可以通过网络访问端点的位置:

#port used to expose actuator
management.port=8081 

#CIDR allowed to hit actuator
management.address=127.0.0.1 

#Whether security should be enabled or disabled altogether
management.security.enabled=false

此外,除了 /info 之外,所有内置端点默认情况下都是敏感的。

如果应用程序使用Spring Security,我们可以通过在 application.properties 文件中定义默认的安全属性(用户名,密码和角色)来保护这些端点:

security.user.name=admin
security.user.password=secret
management.security.role=SUPERUSER

结论

在本文中,我们讨论了Spring Boot Actuator。我们首先定义了Actuator的含义以及它为我们做了什么。

接下来,我们重点介绍了当前Spring Boot 版本2.x的Actuator,讨论了如何使用它,调整它和扩展它。我们还讨论了在这个新的迭代中可以发现的重要安全更改。我们讨论了一些流行的端点以及它们是如何变化的。

然后我们讨论了早期Spring Boot 1版本中的Actuator。

最后,我们演示了如何定制和扩展Actuator。

与往常一样,本文中使用的代码可以在GitHub上找到Spring Boot 2.xSpring Boot 1.x

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值