Spring Boot Actuator官方参考文档(2.5.0)翻译(完结)

背景

乔梁大神曾经在他的《持续交付2.0》一书的第5.1.1节:《持续交付架构要求》中明确指出:为了提升交付速度,获得持续交付能力,系统架构在设计时应该考虑如下因素。

(1)为测试而设计(design for test)。如果我们每次写好代码以后,需要花费很大的精力,做很多的准备工作才能对它进行测试的话,那么从写好代码到完成质量验证就需要很长周期,当然无法快速发布。

(2)为部署而设计(design for development)。如果我们开发完新功能,当部署发布是,需要花费很长时间准备,甚至需要停机才能部署,当然就无法快速发布。

(3)为监控而设计(design for monitor)。如果我们的功能上线以后,无法对齐进行监控,除了问题只能通过用户反馈才发现。那么,持续交付的收益就会大幅降低了。

(4)为扩展而设计(design for scale)。这里的扩展性指两个方面,意识支持团队成员规模的扩展,而是支持系统自身的扩展。

(5)为失效而设计(design for failure)。俗话说:“常在河边走,哪能不湿鞋。”快速地部署发布总会遇到问题。因此,在开发软件功能之前,就应该考虑的一个问题是:一旦部署或发布失败,如何优雅且快速地处理。

在这5个设计原则中,为为监控而设计(design for monitor)属于游戏(服务器)开发中最容易被轻视甚至是忽视的原则之一,而在gamedo.core的开发设计过程中,译者本人也一直在思考如何实现系统监控的最佳实践,直到最近算是确定了技术栈,那就是站在巨人的肩上,使用Spring Boot ActuatorMicroMeter

正是由于gamedo.core最终要选用Spring Boot Actuator作为系统监控的关键技术,因此需要其进行相对深入的研究,这也是本笔记的产生的原因。而本文的所有内容都源于阅读参考文档(Spring Boot版本:2.5.0)以及阅读源码时的随读、随想和随写,为了便于以后查找,章节也完全和参考文档保持一致,并且由于某些章节比较简单,所以就被忽略掉,这可能导致本文的章节不是连续的。

启用产品就绪特性(Enabling Production-ready Features)

Spring Boot的所有产品就绪特性是都是由 spring-boot-actuator模块提供的,开启该特性的最佳方式就是引入专有的Starter,也即:spring-boot-starter-actuator

执行器的定义

执行器(actuator)是一个制造业术语,是指用于移动或控制某些物体的机械设备。可以通过执行器的微小变化带来巨大的变化。

对于使用Maven构建的项目,可以添加如下Starter依赖:

1
2
3
4
5
6
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>

对于使用Gradle的项目,使用如下配置:

1
2
3
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
}

端点(Endpoints)

通过端点可以监控应用程序,和应用程序交互。Spring Boot内置了一堆端点,用户也可以自行添加。比如health端点,它可以提供应用的基本健康信息。

每一个端点都可以被开启、禁用,也可以通过HTTP或JMX的方式暴露给外部。当端点同时开启且被暴露时,它才是可用的。内置的端点也只有在可用状态下才会被Spring Boot自动装配。大多数应用都选择HTTP的方式。端点的ID以及固定前缀/actuator组合成访问该端点的URL。例如对于health端点,其访问方式为:/actuator/health

spring-boot-actuator内置了一大堆开箱即用的端点,详情参考源文档。此外,当应用程序是一个Web应用(Spring MVC、Spring WebFlux或者Jersey),如下内置的额外端点:

端点ID 描述
heapdump 返回一个hprof堆转储文件,需要HotSpot虚拟机支持
jolokia 通过HTTP暴露JMX bean(需要Jolokia在classpath内,且不适用于WebFlux),需要增加jolokia-core依赖
logfile 返回日志文件的内容(如果logging.file.name或logging.file.path属性被设置),并且支持使用HTTP Range头检索部分日志文件的内容
prometheus 将metrics暴露成可以被Prometheus服务器抓取的格式,需要添加micrometer-registry-prometheus依赖

译者提示

  • 对于任意端点来说,可以对其进行两种操作:1、开启或关闭端点;2、通过HTTP或者JMX暴露(exposed)它。当某个端点被开启且被暴露时该端点才处于可用状态。而系统内置端点只有在可用时才会被自动装配。
  • 产品就绪特性属于Spring Boot的六大特性之一,详情可以参考官方文档Features一节
  • 自动装配属于Spring Boot的六大特性之一,简单来说,自动装配就是:如果检测到用户需要某个组件(例如发现引入了某个组件类库),并且用户还没有进行配置,那就启用内部自动装配逻辑,帮用户配置好。例如,如果用户引入了spring-boot-starter-logging,接下来不需要进行一大堆的日志配置,直接记录日志。这个术语会在本文档中多次提及。
  • 端点(Endpoints)和指标(metrics)是本文最重要的两个概念,占据了本文的大部分篇幅。端点的概念不难理解,属于Spring Boot Actuator的核心功能,从系统内部代码层面讲,就是一个个内置的自动装配的以及用户自定义的端点 bean,从外部用户角度讲,就是一个个可以访问的数据集合窗口(可以通过jmx或http)。而指标有时候指的就是众多端点中的metrics端点,有时候指的是metrics端点下的被Spring Boot使用micrometer采集到的指标。理解了这些,实际上就理解整篇文章的精髓。

开启端点(Enabling Endpoints)

默认情况下,除了shutdown端点,其他所有端点默认处于开启状态。如果要开关某个端点,可以配置:management.endpoint.<端点id>.enabled,例如开启shutdown端点的配置为:

1
2
3
4
management:
endpoint:
shutdown:
enabled: true

如果希望所有端点默认都是关闭状态,可以将management.endpoints.enabled-by-default配置为false,然后将某端点的enabled属性配置为true来单独开启。以info端点举例(只开启info端点,其他端点都关闭):

1
2
3
4
5
6
management:
endpoints:
enabled-by-default: false
endpoint:
info:
enabled: true

提示

当某个端点被关闭后,对应的端点bean会从Spring容器(application context)中移除。如果仅仅是不想让某个端点被暴露,可以使用include和exclude属性。

暴露端点(Exposing Endpoints)

因为端点可能会包含敏感信息,因此在决定暴露端点前需要仔细考虑。下表展示了内置端点的默认暴露状态(简而言之:JMX下默认全开,HTTP下只有health开启):

ID JMX Web
auditevents Yes No
beans Yes No
caches Yes No
conditions Yes No
configprops Yes No
env Yes No
flyway Yes No
health Yes Yes
heapdump N/A No
httptrace Yes No
info Yes No
integrationgraph Yes No
jolokia N/A No
logfile N/A No
loggers Yes No
liquibase Yes No
metrics Yes No
mappings Yes No
prometheus N/A No
quartz Yes No
scheduledtasks Yes No
sessions Yes No
shutdown Yes No
startup Yes No
threaddump Yes No

如果想调整某个端点的暴露状态,可以使用如下includeexclude属性:

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

include属性列出的是需要开启暴露的端点的id集合,而exclude属性列出的是关闭暴露的端点的id集合。exclude的优先级高于include,且这两个属性都可以配置为一个以端点ID列表。

例如,如果只想通过JMX暴露healthinfo端点,而禁止暴露其他端点,可以使用如下配置:

1
2
3
4
5
management:
endpoints:
jmx:
exposure:
include: "health,info"

*代表所有端点。例如,如果想通过HTTP的方式暴露除了envbeans之外的所有端点,可以使用如下配置:

1
2
3
4
5
6
management:
endpoints:
web:
exposure:
include: "*"
exclude: "env,beans"

提示

  • *在YAML中具有特殊含义,因此在includeexclude中使用时需要添加双引号
  • 如果应用程序暴露在外网环境中,强烈建议加固HTTP端点
  • 如果想自定义端点的暴露策略,可以注册一个EndpointFilter bean

加固HTTP端点(Securing HTTP Endpoints)

信息敏感的URL需要进行安全加固,而对于HTTP方式的端点也应该得到相同待遇的处理。如果使用了Spring Security,端点默认会被Spring Security的内容协商策略(content-negotiation strategy)加固,例如只允许具有某种角色(role)的用户访问。Spring Boot提供了一些方便使用的RequestMatcher对象,可以配合Spring Security使用。

典型的Spring Security配置如下所示:

1
2
3
4
5
6
7
8
9
10
11
@Configuration(proxyBeanMethods = false)
public class MySecurityConfiguration {

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.requestMatcher(EndpointRequest.toAnyEndpoint())
.authorizeRequests((requests) -> requests.anyRequest().hasRole("ENDPOINT_ADMIN"));
http.httpBasic();
return http.build();
}
}

上面的例子中,EndpointRequest.toAnyEndpoint()用来匹配任意端点,然后还会确保用户拥有ENDPOINT_ADMIN角色。EndpointRequest中还有其他类似的匹配函数。可以查看API文档(HTMLPDF)获得更多详情。

如果应用程序部署在防火墙后面,可以允许所有端点被访问而无需进行鉴权。此时可以将management.endpoints.web.exposure.include配置为*****,如下所示:

1
2
3
4
5
management:
endpoints:
web:
exposure:
include: "*"

此外,如果使用了Spring Security,并且想允许未经过身份验证的访问,还需要一些自定义配置,例如:

1
2
3
4
5
6
7
8
9
10
@Configuration(proxyBeanMethods = false)
public class MySecurityConfiguration {

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.requestMatcher(EndpointRequest.toAnyEndpoint())
.authorizeRequests((requests) -> requests.anyRequest().permitAll());
return http.build();
}
}

提示

以上两个例子中的配置仅对端点请求生效。而对于Spring Boot来说,当存在用户自定义的SecurityFilterChain bean时,其安全配置就会自动失效。因此需要配置额外的SecurityFilterChain来适配应用程序的其他请求

配置端点(Configuring Endpoints)

对于端点中不包含参数的读操作(read operations)请求,端点会自动缓存响应数据(response),如果要修改某端点的缓存时间,可以配置cache.time-to-live 属性,如下配置就是将beans端点的缓存时间改成10秒:

1
2
3
4
5
management:
endpoint:
beans:
cache:
time-to-live: "10s"

提示

management.endpoint.<name>前缀用于标识要配置的端点

Hypermedia for Actuator Web Endpoints

跨域资源共享支持(CORS Support)

跨域资源共享(CORS)是一个W3C规范,可以协助制定灵活的跨域访问授权策略。如果你在使用Spring MVC或者Spring WebFlux,Web端点可以支持支持中场景。

CORS默认是被关闭的,并且只有management.endpoints.web.cors.allowed-origins被配置后才会开启,下面配置允许来自于example.comGETPOST请求:

1
2
3
4
5
6
management:
endpoints:
web:
cors:
allowed-origins: "https://example.com"
allowed-methods: "GET,POST"

提示

CorsEndpointProperties查看完整的属性列表

实现自定义端点(Implementing Custom Endpoints)

如果一个@Bean@Endpoint注解,那么任意被注解了@ReadOperation@WriteOperation或者@DeleteOperation的方法都以JMX方式暴露,而对于Web应用程序,则会以HTTP的方式暴露。当使用Jersey、Spring MVC或者Spring WebFlux时,端点可以通过HTTP暴露。当Jersey和Spring MVC都可用时,Spring MVC优先被使用。

以下例子暴露一个读操作(read operation),该操作返回了一个自定义对象

1
2
3
4
@ReadOperation
public CustomData getData() {
return new CustomData("test", 5);
}

可以使用@JmxEndpoint@WebEndpoint注解来开启特定方式的端点(JMX或者Web)。

可以使用@EndpointWebExtension@EndpointJmxExtension,这两个注解可以对特定方式的端点进行增强(JMX或者Web)

笔者提示

对于注解了@Endpoint@Bean,由于既可以通过JMX方式暴露,又可以通过HTTP的方式暴露(后文称这种端点为原生端点)。为了兼容性的需要,不得不放弃某些技术特性。因此Spring设计了@EndpointWebExtension@EndpointJmxExtension(从Spring Boot 2.2.0开始,还增加了@EndpointCloudFoundryExtension注解),这些注解的作用对原生端点进行技术特级别的扩展。例如对于以HTTP方式暴露的某个端点,可以为响应数据(Response)增加一个状态码(而JMX方式就不需要这个状态码),那么就可以使用@EndpointWebExtension对原生端点进行二次加工,示例可以参考源码中EnvironmentEndpointWebExtension的实现

最后,如果需要使用web框架相关的功能,可以实现Servlet或者使用Spring @Controller@RestController端点,不过代价是通过JMX方式暴露就不可用,并且当使用其他web框架时也不可用。

入参处理(Receiving Input)

通过参数的方式,端点的操作(Operations)来接收输入。当通过web暴露时,这些参数来自于请求的查询参数或者请求body中的JSON对象。当通过JMX暴露时,这些参数从MBean映射而来。默认情况下,参数是必须输入的。不过可以通过添加注解@javax.annotation.Nullable@org.springframework.lang.Nullable使之成为可选参数。

对于web请求body中JSON对象,每个属性值都可以被映射为端点的一个参数,例如请求body中的json结构为:

1
2
3
4
{
"name": "test",
"counter": 42
}

那么可以开发这么一个包含String nameint counter参数的端点与之对应,例如:

1
2
3
4
@WriteOperation
public void updateData(String name, int counter) {
// injects "test" and 42
}

提示

  • 由于原生端点的兼容性需要,因此端点的入参只能是基本类型,因此不支持将namecounter封装到CustomData
  • 如果想要将输入参数映射到函数的参数上,当编译Java代码时,需要使用-parameters参数,而对于Kotlin代码,则需要使用-java-parameters,如果在Gradle中使用了Spring Boot的插件或者在Maven中使用了spring-boot-starter-parent这个参数已经被自动开启。(关于-parameters的更多细节,可以参考StackOverflow的这个解答)

输入类型转换

在必要的情况下,传给端点的参数会被自动转换为端点的参数类型。在调用端点的操作函数(operation method)之前,通过JMX或HTTP请求的参数通过ApplicationConversionService对象和任意被@EndpointConverter注解标识的ConverterGenericConverter转换。

自定义Web端点(Custom Web Endpoints)

@Endpoint@WebEndpoint@EndpointWebExtension注解的端点会自动通过Jersey、Spring MVC或Spring WebFlux以HTTP的方式暴露。而如果Jersey和Spring MVC都可用,那么Spring MVC会被启用。

Web端点请求谓词(Web Endpoint Request Predicates)

对于每个HTTP端点的任意操作(operation),都会自动生成一个HTTP请求谓词

路径(Path)

请求谓词的路径取决于端点的ID和根路径(指的是以web方式暴露的根路径),默认的根路径是/actuator。例如,sessions端点的谓词路径就是/actuator/sessions

可以通过在端点的函数入参上增加@Selector注解实现路径的自定义解析。这些解析后的请求参数会被以路径变量的方式加入到请求谓词中。当端点的函数被调用时,这些路径变量会被当做入参传入。如果想捕获完整路径上所有剩余元素(每个被“/”分割的字符串都是一个元素),可以在最后一个函数入参上使用@Selector(Match=ALL_REMAINING)注解,这会把所有的元素转换为String[]数组。

HTTP方法(HTTP method)

请求谓词中的HTTP方法取决于操作类型,如下表所示:

操作类型 HTTP方法
@ReadOperation GET
@WriteOperation POST
@DeleteOperation DELETE

请求媒体类型(Consumes)

对于HTTP POST方式的@WriteOperation,其请求(Request)的媒体类型(Content-Type)为application/vnd.spring-boot.actuator.v2+json, application/json,而其他操作类型则为空。

响应媒体类型(Produces)

响应(Response)的媒体类型由@DeleteOperation@ReadOperation@WriteOperation注解内的produces属性决定。这个属性是可选的,如果没有配置,那么媒体类型会被自动设置。

如果操作函数的返回值是void或者Void,那么媒体类型为空。如果返回一个org.springframework.core.io.Resource,那么媒体类型类型为application/octet-stream(也即二进制流数据)。而其他的所有的操作,媒体类型都是application/vnd.spring-boot.actuator.v2+json, application/json

Web端点的响应状态码(Web Endpoint Response Status)

默认的响应状态码取决于操作类型(@DeleteOperation@ReadOperation@WriteOperation)和返回值(如果有返回值的话)。

  • 如果一个@ReadOperation返回了一个值,那么状态码是200(OK)。否则的话,状态码是404(Not Found)。

  • 如果一个@WriteOpertion@DeleteOperation返回了一个值,那么状态码是200(OK)。否则的话,状态码是204(No Cpmtemt)。

  • 如果一个操作被调用了而没有传入必须的参数,或者说参数没有被正确转换,那么操作函数将不会被调用,返回一个400(Bad Request)状态码

Web端点范围请求(Web Endpoint Range Requests)

可以使用HTTP范围请求来获取HTTP资源。当使用Spring MVC或Spring WebFlux时,如果某个操作返回了org.springframework.core.io.Resource,那么范围请求会被自动支持。

提示

Jersey不支持范围请求

Web端点安全(Web Endpoint Security)

对于web方式的端点或者web相关的端点扩展(web-specific endpoint extension),它们都可以接收java.security.Principalorg.springframework.boot.actuate.endpoint.SecurityContext作为操作函数的参数。前者通常配合@Nullable使用,为经过身份验证和未经过身份验证的用户提供不同的行为。而后者通常使用isUserInRole(Sring)进行权限检查

Servlet端点(Servlet Endpoints)

当同时满足如下两个条件后,就可以实现一个Servlet端点:

  • 实现一个Supplier<EndpointServlet>
  • 同时该类上增加@ServletEndpoint注解

Servlet端点可以和Servlet容器更深层地集成,但是牺牲了可移植性。这种方式的应用场景就是可以将已有的Servlet转化为端点。而对于新的端点,仍然尽量使用@Endpoint@WebEndpoint

Controller端点(Controller Endpoints)

@ControllerEndpoint@RestControllerEndpoint端点只可以在Spring MVC和Spring WebFlux下使用。当使用Spring MVC或Spring WebFlux的标准注解,例如@RequestMapping@GetMapping时,端点的操作方法都可以被正常映射,并且以端点的ID作为请求路径(path)的前缀。Controller端点提供了和Srping web框架更深的集成度,然而牺牲了可移植性。因此,尽量优先使用@Endpoint@WebEndpoint端点。

健康信息(Health Information)

可以通过健康信息检查应用程序的运行状态。健康信息通常被用来监控应用,并且在系统宕机时进行报警。health端点暴露的信息详情取决于management.endpoint.health.show-detailsmanagement.endpoint.health.show-components属性的配置,可以配置的值如下所示:

配置值 描述
never(默认值) 详情不可见
when-authorized 详情仅对授权用户可见。授权用户可以通过management.endpoint.health.roles配置
always 详情对所有用户可见

当一个用户拥有一个或多个端点角色(endpoint’s roles)时,他被认为是授权的。如果某个端点没有配置角色(这是默认状态),那么所有通过身份认证的用户都任务是被授权的。可以通过management.endpoint.health.roles配置角色。

提示

如果已经对应用程序进行安全控制( secured your application),而想使用always配置,那么需要对安全配置进行设置,是的所有经过身份认证和未经过身份认证的用户都获得访问权限

健康信息是 HealthContributorRegistry中收集所有健康数据的集合。默认情况下,这些健康数据是Spring上下文(ApplicationContext)中一个个HealthContributor实例,Spring Boot已经自动装配了很多HealthContributors,用户也可以自己实现。

HealthContributor既可以是一个HealthIndicator 也可以是一个CompositeHealthContributor,前者提供了实际的健康数据,并包含一个Status,后者提供了和其他HealthIndicator组合的能力。最终,所有这些HealthContributor形成了一个树状结构,来展示整个系统的健康状态。

默认情况下,系统的最终健康状态由Statusaggregator计算获得。Statusaggregator的实现类SimpleStatusAggregator的实现算法:

  • 内部维护了一个健康状态的有序列表,排序为:DOWNOUT_OF_SERVICEUPUNKNOWN
  • 对于外部传入的状态集合,首先过滤掉不识别的状态码(也即只保留这4个状态码)
  • 算出每个状态在有序列表中的索引,并取出索引值最小的状态,作为最终状态(实际上就是跟进有序列表的顺序进行排序)
  • 如果剩下的集合是空的,那么返还一个UNKNOWN状态(这种情形只发生所有传入的状态都不属于这4种状态的情况下)

提示

HealthContributorRegistry可以在运行状态下动态注册和反注册

自动装配的HealthIndicators(Auto-configured HealthIndicators)

Spring Boot已经自动装配了很多HealthIndicator,可以通过management.health.<key>.enabled将其开启或关闭

提示

  • 详细的HealthIndicator列表不再赘述,详情参考源文档
  • 可以通过设置management.health.defaults.enabled关闭所有的HealthIndicator

以下HealthIndicator也是可用的,但是默认情况下没有被启用:

Key 名字 描述
livenessstate LivenessStateHealthIndicator 暴露应用程序的活性状态
readinessstate ReadinessStateHealthIndicator 暴露应用程序的就绪状态

笔者提示

  • 关于活性状态,Spring Boot在源码中有详细的解释:当应用程序的内部状态是正确的(CORRECT),那么它被认为是存活的。而失活状态意味着应用程序内部状态已经出现严重异常(BROKEN)而且无法正常恢复,只能通过重启应用解决该异常。相应地,活性状态有两个状态,分别为:CORRECTBROKEN
  • 关于就绪状态,Spring Boot在源码中也有详细的解释:当应用程序处于存活(也即活性状态为CORRECT)状态且可以接受流量时,被认为是就绪的(ACCEPTING_TRAFFIC)。而当应用程序无法接受流量时意味着就绪失败(REFUSING_TRAFFIC),基础设施必须停止对其路由。相应地,就行状态也包含两种:ACCEPTING_TRAFFICREFUSING_TRAFFIC(也就是说就绪状态更倾向于一个web术语)

自定义HealthIndicators(Writing Custom HealthIndicators)

可以通过注册 HealthIndicator 接口的Bean实现自定义的监控数据。该接口类需要实现health()方法并且返回一个Health类。该返回值必须包含一个状态,并且可选择性地包含详细信息以供显示。以下代码展示了一个HealthIndicator实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Component
public class MyHealthIndicator implements HealthIndicator {

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

private int check() {
// perform some specific health check
return ...
}
}

提示

HealthIndicator接口类的名字去掉HealthIndicator后缀(如果存在的话)会作为Bean的名字,上述实例中,这个自定义HealthIndicator的名字是my。

除了Srping Boot内置的Status之外,返回的Health内也可以使用自定义的状态。在这种情况下,需要实现一个自定义的StatusAggregator ,或者对management.endpoint.health.status.order属性进行配置,来替代默认的状态配置。

例如,假如在某个HealthIndicator内返回了一个自定义状态:FATAL,为了配置优先级,需要增加如下配置:

1
2
3
4
5
management:
endpoint:
health:
status:
order: "fatal,down,out-of-service,unknown,up"

HTTP的响应状态码反映了系统的整体监控状态。默认情况下,OUT_OF_SERVICEDOWN的状态码是503。所有没有配置映射的健康状态(包括UP),其状态码为200。如果对自定义健康状态的状态码进行了配置,那么DOWNOUT_OF_SERVICE的默认状态码会被禁用。如果仍然想保留这些配置,需要和自定义的状态一起进行显式地定义。下面的例子中,将FATAL映射为503(service unavailable),并且保留了DOWNOUT_OF_SERVICE的原有的配置

1
2
3
4
5
6
7
8
management:
endpoint:
health:
status:
http-mapping:
down: 503
fatal: 503
out-of-service: 503

提示

如果想要更多控制权,可以实现一个自定义的HttpCodeStatusMapper Bean

以下表格展示了内置状态的默认映射配置:

状态
DOWN SERVICE_UNAVAILABLE (503)
OUT_OF_SERVICE SERVICE_UNAVAILABLE (503)
UP 默认没有映射,所以状态码是200
UNKNOWN 默认没有映射,所以状态码是200

响应式健康指示器(Reactive Health Indicators)

对于响应式的应用,例如使用了Spring WebFlux,ReactiveHealthContributor提供了非阻塞的契约来获得应用的健康信息。和传统的HealthContributor很类似,其健康信息收集自ReactiveHealthContributorRegistry(默认情况下,所有的 HealthContributorReactiveHealthContributor 实例都在ApplicationContext中)。在弹性调度器下(elastic scheduler),常规的HealthContributors并不会调用响应式的API。

提示

在响应式应用中,ReactiveHealthContributorRegistry应该在运行时状态下注册或反注册健康指示器(health indicators),如果想注册常规的HealthContributor,需要使用ReactiveHealthContributor#adapt对其包装。

如果想通过响应式API提供自定义健康指示器(health indicators),可以注册实现了ReactiveHealthIndicator 接口的Bean到Spring容器中,以下代码展示了一个ReactiveHealthIndicator的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Component
public class MyReactiveHealthIndicator implements ReactiveHealthIndicator {

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

private Mono<Health> doHealthCheck() {
// perform some specific health check
return ...
}
}

提示

如果想自动处理异常错误,可以继承AbstractReactiveHealthIndicator

自动装配的ReactiveHealthIndicators(Auto-configured ReactiveHealthIndicators)

Spring提供了一些内置的响应式健康指示器(ReactiveHealthIndicators),当它们可以可用时(端点被开启且被正常暴露时即为可用),会被自动装配。详情参考源文档第2.8.4节的表格,此处不再赘述

提示

在必要的情况下,响应式的指示器会替代非响应式的指示器。并且任何没有被处理过的HealthIndicator也会被自动包装为响应式

健康分组(Health Groups)

处于某些原因,将健康指示器进行分组是很有用的。

可以创建management.endpoint.health.group.<name>属性来创建一个健康分组。并且使用includeexclude属性来配置指示器ID。例如,假如想创建一个仅仅包含数据库指示器的分支,可以配置如下:

1
2
3
4
5
6
management:
endpoint:
health:
group:
custom:
include: "db"

然后可以通过链接:localhost:8080/actuator/health/custom访问该分组

同理,如果想创建一个不包含数据库指示器的分组,可以配置如下:

1
2
3
4
5
6
management:
endpoint:
health:
group:
custom:
exclude: "db"

默认情况下,如同系统的健康信息一样,分组沿用了相同的StatusAggregatorHttpCodeStatusMapper设置。不过这些设置可以在每个分组上单独定义。如果有需要的话,还可以覆盖show-detailsroles的配置,例如:

1
2
3
4
5
6
7
8
9
10
11
12
management:
endpoint:
health:
group:
custom:
show-details: "when-authorized"
roles: "admin"
status:
order: "fatal,up"
http-mapping:
fatal: 500
out-of-service: 500

提示

如果想将自定义的StatusAggregatorHttpCodeStatusMapper Bean注册到某个分组上,可以使用注解@Qualifier("groupname")对其进行限定

数据源健康(DataSource Health)

DataSource健康指示器用来展示标准数据源(standard data source)类型和路由数据源(routing data source)类型的Bean的健康信息。路由数据源的健康信息也包含了目标数据源(its target data sources)的健康信息。在监控信息端点的HTTP响应中,每一个路由数据源的目标数据源的名字,由路由键值(routing key)来决定。如果想把路由数据源排除,可以将management.health.db.ignore-routing-data-sources设置为true

Kubernetes探针(Kubernetes Probes)

部署在Kubernetes上的应用程序可以通过容器探针反馈内部状态信息。kubelet可以根据Kubernetes的配置调用这些探针并反馈探针结果。

Spring Boot提供了开箱即用的应用程序可用性状态管理。当应用程序被部署到Kubernetes环境下,Spring Boot Acuator会通过ApplicationAvailability接口收集“Liveness”和“Readiness”信息,并且在健康指示器LivenessStateHealthIndicatorReadinessStateHealthIndicator中使用这些信息。这些指示器的信息显示在全局端点("/actuator/health")中。也可用通过使用健康分组"/actuator/health/liveness""/actuator/health/readiness" 访问这些端点。

可以使用如下端点信息配置Kubernetes:

1
2
3
4
5
6
7
8
9
10
11
12
13
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: <actuator-port>
failureThreshold: ...
periodSeconds: ...

readinessProbe:
httpGet:
path: /actuator/health/readiness
port: <actuator-port>
failureThreshold: ...
periodSeconds: ...

提示

<actuator-port>应该被配置为一个可以被访问的端口号。可以将其配置为web服务器的端口,或者通过management.endpoint.health.probes.enabled配置,使用独立的端口

这些健康分组只有在应用程序运行在Kubernetes环境下时才会自动生效。当然,也可以通过配置management.endpoint.health.probes.enabled来开启这些功能。

提示

如果应用程序的启动时间比liveness指示器所反映的时间要长,Kubernetes提供了一个“startupProbe”探针作为替代方案。不过“startupProbe”探针并不一定必须配置,因为在所有的启动任务完成之前"readinessProbe"探针都处于失败状态。可以查看探针在应用程序生命周期中的行为

警告

如果端点(Actuator endpoints)被配置在独立的Spring上下文(a separate management context)中,需要注意的是,这些端点使用的web配置信息(端口、连接池、框架的组件等)也是独立于应用程序的。在这种情况下,即使应用程序已经无法正常工作(例如无法接受新连接),探针可能也会返回正常状态。

使用Kubernetes探针检测外部状态(Checking External State with Kubernetes Probes)

Spring Boot Actuator将“活性”(liveness)和“就绪”(readiness)探针配置为健康分组。这意味着对于这些探针来说,所有的健康分组特性都适用。例如,可以配置如下健康指示器:

1
2
3
4
5
6
management:
endpoint:
health:
group:
readiness:
include: "readinessState,customCheck"

默认情况下,Spring Boot没有将其他的健康指示器添加到这些健康分组中。

“活性”(liveness)探针的健康检测不应该依赖于外部系统(笔者注:例如mongoDB、Redis等),如果应用程序的活性状态处于当宕机状态,Kubernetes会尝试重新启动应用程序来解决这个问题。也就是说如果外部系统出现异常(例如数据库、Web API或外部缓存),那么Kubernetes会重启所有的应用程序,这会导致级联故障(笔者注:雪崩效应)

而对于“就绪”探针来说,开发人员必须谨慎处理外部系统的检测结果。比如Srping Boot就没有包含任何额外的健康检查。如果应用程序的就绪状态处于未就绪(unready)状态,Kubernetes就不会将流量路由到该应用。那么把这些状态加入到“就绪”探针的探测中是理应该的。某些外部系统可能不是应用程序的关键依赖(比如应用程序已经部署了熔断或者降级策略),在这种情况下,这些外部系统就绝不应该被包含到“就绪”探针中。不妙的是,外部系统都是作为通用模块被应用程序所依赖的,这就需要做一个抉择:将其加入到“就绪”探针,当外部系统发生故障时,让应用程序也停止服务(out of service);或者将这些外部系统排除在外,在外部系统发生故障时,从更高层级上处理这些故障,比如使用断路器。(Unfortunately, an external system that is shared by all application instances is common, and you have to make a judgement call: include it in the readiness probe and expect that the application is taken out of service when the external service is down, or leave it out and deal with failures higher up the stack, e.g. using a circuit breaker in the caller.)

提示

If all instances of an application are unready, a Kubernetes Service with type=ClusterIP or NodePort will not accept any incoming connections. There is no HTTP error response (503 etc.) since there is no connection. A Service with type=LoadBalancer might or might not accept connections, depending on the provider. A Service that has an explicit Ingress will also respond in a way that depends on the implementation - the ingress service itself will have to decide how to handle the “connection refused” from downstream. HTTP 503 is quite likely in the case of both load balancer and ingress.

此外,如果应用程序使用了Kubernetes的自动伸缩(autoscaling)机制,对于负载均衡后面的程序,探针的表现可能会不同,这要取决于自动伸缩的配置。

应用程序生命周期和探针状态(Application Lifecycle and Probe States)

Kubernetes探针所支持的重要一点就是保持了和应用程序生命周期的一致性。应用程序内存中的内部状态:AvailabilityState和探针实际上返回的状态可能会有巨大的差异:在生命周期的某些阶段,探针可能是不可用状态。

当应用启动和关闭时,Sprin Boot会发布事件,探针可以监听这些事件,并且暴露AvailabilityState信息。

下面表格展示了在不同阶段下,AvailabilityState和HTTP服务器的状态,当Spring Boot应用程序启动时:

启动阶段 活性状态 就绪状态 HTTP服务器 备注
Starting BROKEN REFUSING_TRAFFIC 未启动 Kubernetes检查“活性”探针,如果耗时过长,就重启应用程序。
Started CORRECT REFUSING_TRAFFIC 拒绝连接 应用程序上下文已经刷新,应用程序执行启动任务并且还不能接收流量
Ready CORRECT ACCEPTING_TRAFFIC 接受连接 启动任务已经执行完毕,应用程序可以接收流量

当Spring Boot应用程序关闭时:

关闭阶段 活性状态 就绪状态 HTTP服务器 备注
Running CORRECT ACCEPTING_TRAFFIC 接受连接 (此时)已经接受关闭请求
Graceful shutdown CORRECT REFUSING_TRAFFIC 不接受新连接 如果启用该特性,将会根据请求优雅地关闭进程
Shutdown complete N/A N/A 服务器关闭 应用程序上下文被关闭并且应用也被关闭

提示

查看 Kubernetes容器生命周期查看关于Kubernetes部署更多的细节

应用程序信息(Application Information)

应用程序信息可以暴露ApplicationContext内所有的InfoContributor Bean收集到的信息。Spring Boot内置了很多自动装配的InfoContributor Bean,并且用户也可以编写自定义的Bean

自动装配InfoContributors(Auto-configured InfoContributors)

在适当的情况下,如下InfoContributor类型的Bean会被自动装配:

名称 描述
EnvironmentInfoContributor 暴露Environment内所有info开头的属性(笔者注:例如配置在application.yaml内的info.name: myApp )
GitInfoContributor 如果git.properties文件存,则暴露git相关信息
BuildInfoContributor 如果META-INF/build-info.properties文件存在,则暴露构建相关信息

提示

可以通过配置management.info.defaults.enabled关闭上述任意端点

自定义应用程序信息(Custom Application Information)

可以通过在Spring配置文件中设置info.*配置暴露自定义的数据。所有的Environment属性下info开头的键值都会被自动暴露。例如,可以在application.properties下增加如下配置:

1
2
3
info.app.encoding=UTF-8
info.app.java.source=11
info.app.java.target=11

提示

除了上述硬编码,还可以在构建期间生成属性值

以Maven为例,可以将上述配置重写为:

1
2
3
info.app.encoding=@project.build.sourceEncoding@
info.app.java.source=@java.version@
info.app.java.target=@java.version@

Git提交信息(Git Commit Information)

另外一个有用的info端点是展示源码所在的git仓库的提交信息。当GitProperties Bean存在时,这些信息就可以在info端点下暴露出来。

提示

如果classpath根路径下面存在一个git.properties文件,GitProperties Bean会被自动装配,可以通过“生成git信息”获得更多细节

默认情况下,在属性存在的前提下,端点会暴露出git.branchgit.commit.idgit.commit.time。如果想关闭任意属性,需要在git.properties中排除掉。如果想展示完整的git信息(也就是说git.properties文件的所有内容),可以配置management.info.git.mode属性,如下所示:

1
2
3
4
management:
info:
git:
mode: "full"

如果想从info端点关闭git提交信息,可以通过将management.info.git.enabled属性设置为false,如下所示:

1
2
3
4
management:
info:
git:
enabled: false

构建信息(Build Information)

如果BuildProperties Bean存在,还可以暴露构建信息,并且当classpath下存在META-INF/build-info.properties文件时生效。

提示

Maven和Gradle插件都可以生成META-INF/build-info.properties文件,可以通过“Generate build information”或多更多细节

自定义InfoContributors(Writing Custom InfoContributors)

可以通过注册继承了 InfoContributor接口的Bean实现自定义的应用信息。如下所示:

1
2
3
4
5
6
7
8
@Component
public class MyInfoContributor implements InfoContributor {

@Override
public void contribute(Info.Builder builder) {
builder.withDetail("example", Collections.singletonMap("key", "value"));
}
}

如果访问info端点,将会看到如下的额外信息:

1
2
3
4
5
{
"example": {
"key" : "value"
}
}

通过HTTP进行监控与管理(Monitoring and Management over HTTP)

如果你正在开发一个Web应用程序,Srping Boot Actuator会自动装配所有已经开启(enabled)的端点,使通过HTTP暴露。默认规则是通过端点的id附加一个/actuator前缀作为URL路径。例如,health端点的路径为/actuator/health

提示

  • Spring Boot Actuator被Spring MVC、Spring WebFlux和 Jersey原生支持。如果Jersey和Spring MVC都处于可用状态,那么将会使用Spring MVC。
  • 为了获得如API文档 (HTMLPDF)中所述的正确JSON响应,需要将Jackon加入到依赖中

自定义端点路径(Customizing the Management Endpoint Paths)

某些情况下,自定义端点路径的前缀是很有必要的。比如,应用程序可能已经使用了/actuator路径作为其他用途。可以设置management.endpoints.web.base-path属性来调整端点的前缀,如下所示:

1
2
3
4
management:
endpoints:
web:
base-path: "/manage"

这会将端点的URL从/actuator/{id} 改为/manage/{id}(例如:/manage/info

提示

除非管理端口被配置为其他的的HTTP端口,否则management.endpoints.web.base-path的配置是相对于server.servlet.context-path(Servlet web应用)或spring.webflux.base-path(响应式web应用)的。如果management.server.port被配置了,那么management.endpoints.web.base-path是相对于management.server.base-path的路径。

如果想将端点映射到其他路径,可以修改management.endpoints.web.path-mapping属性,以下示例将/actuator/health映射为/healthcheck

1
2
3
4
5
6
management:
endpoints:
web:
base-path: "/"
path-mapping:
health: "healthcheck"

自定义端口(Customizing the Management Server Port)

如果应用程序是基于云部署,那么使用默认的HTTP端口来暴露端点是一个明智的选择。不过,如果应用程序运行在自己内部的数据中心,可能会倾向于使用其他的HTTP端口。

可以通过设置management.server.port属性调整HTTP端口,如下所示:

1
2
3
management:
server:
port: 8081

提示

在Cloud Foundry上,默认情况下,应用程序只在端口8080上接收HTTP和TCP路由请求。如果想在Cloud Foundry上使用自定义的端口,你需要明确地设置应用程序的路由,将流量转发到自定义端口。

配置SSL(Configuring Management-specific SSL)

当使用了自定义端口之后,也可以通过management.server.ssl.*属性配置独立的SSL。例如,可以让端点管理通过HTTP访问,而应用程序通过HTTPS访问,如下配置所示:

1
2
3
4
5
6
7
8
9
10
11
server:
port: 8443
ssl:
enabled: true
key-store: "classpath:store.jks"
key-password: secret
management:
server:
port: 8080
ssl:
enabled: false

又或者,端点管理和应用程序都通过SSL访问,但是使用不同的证书和秘钥(keystore),如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
server:
port: 8443
ssl:
enabled: true
key-store: "classpath:main.jks"
key-password: "secret"
management:
server:
port: 8080
ssl:
enabled: true
key-store: "classpath:management.jks"
key-password: "secret"

自定义服务器地址

通过设置management.server.address属性,可以自定义端点的访问地址。如果只想监听内部网络或运维内部网络(ops-facing network ),有或者只想监听来来自localhost的连接,这个设置就会很有用。

提示

只有当端点端口与应用程序端口不同时,才可以配置监听不同的地址。

如下配置不允许远程连接访问:

1
2
3
4
management:
server:
port: 8081
address: "127.0.0.1"

禁用HTTP端点(Disabling HTTP Endpoints)

如果不想通过HTTP暴露端点,可以将端口设置为-1,例如:

1
2
3
management:
server:
port: -1

也可以通过设置management.endpoints.web.exposure.exclude属性达到达到这个效果。如下配置所示:

1
2
3
4
5
management:
endpoints:
web:
exposure:
exclude: "*"

通过JMX进行监控和管理(Monitoring and Management over JMX)

JAVA管理扩展(JMX)提供了管理和监控应用程序的标准机制。这个特性默认没有被启用,可以通过设置spring.jmx.enabledtrue来开启。默认情况下,Spring Boot的JMX MBeans位于org.springframework.boot作用域下。要想完全控制JMX域下的端点,可以考虑实现EndpointObjectNameFactory接口。

自定义MBean名字(Customizing MBean Names)

通常情况下,MBean的名字由端点的id生成。例如,health端点就被暴露为:org.springframework.boot:type=Endpoint,name=Health

如果应用程序拥有的ApplicationContext不止一个的话,可能会发现名称冲突。若要解决该问题,可以设置属性spring.jmx.unique-namestrue,这样的话,MBean的名字就是唯一的了。

可以自定义暴露端点的JMX作用域,如下例所示:

1
2
3
4
5
6
7
spring:
jmx:
unique-names: true
management:
endpoints:
jmx:
domain: "com.example.myapp"

禁用JMX端点(Disabling JMX Endpoints)

如果不想通过JMX暴露端点,可以设置management.endpoints.jmx.exposure.exclude属性为*,如下所示:

1
2
3
4
5
management:
endpoints:
jmx:
exposure:
exclude: "*"

通过HTTP访问基于Jolokia的JMX端点(Using Jolokia for JMX over HTTP)

Jolokia作为一个JMX-HTTP桥接器提供了访问JMX bean的替代方案。如果想要使用Jolokia,需要添加依赖:org.jolokia:jolokia-core。以Maven为例,配置如下所示:

1
2
3
4
<dependency>
<groupId>org.jolokia</groupId>
<artifactId>jolokia-core</artifactId>
</dependency>

可以通过添加jolokia*management.endpoints.web.exposure.include属性中开启Jolokia端点。然后可以使用/actuator/jolokia该端点。

提示

Jolokia端点将Jolokia的servlet暴露为actuator端点。这意味着它是特定于Spring MVC和Jersey等servlet环境的。并且该端点在WebFlux应用程序中不可用。

自定义Jolokia(Customizing Jolokia)

Jolokia包含许多设置,通常可以是通过设置servlet参数进行配置。而在Spring Boot下中,可以使用application.properties。所有的Jolokia参数都以management.endpoint.jolokia.config作为前缀,举例如下:

1
2
3
4
management:
endpoint:
jolokia:
enabled: false

禁用Jolokia(Disabling Jolokia)

当使用了Jolokia而又不想让Spring Boot对其进行配置,可以将management.endpoint.jolokia.enabled设置为false,如下所示:

1
2
3
4
management:
endpoint:
jolokia:
enabled: false

日志(Loggers)

Spring Boot Actuator具备查看和设置正在运行中的应用程序的日志等级的能力。可以查看完整日志列表或者单独某个日志的配置,这些配置由两部分组成:显式配置的日志等级和日志框架给定的有效日志等级。这些日志等级可以是如下任意一个:

  • TRACE
  • DEBUG
  • INFO
  • WARN
  • ERROR
  • FATAL
  • OFF
  • null

null代表没有显示地配置日志

配置日志(Configure a Logger)

如果要配置一个日志,可以向资源URL POST一个特定的请求体,如下所示:

1
2
3
{
"configuredLevel": "DEBUG"
}

提示

如果想重置之前设置的日志等级(并且使用默认配置),可以将configuredLevel设置为null

指标(Metrics)

Spring Boot Actuator提供了对 Micrometer的依赖管理和自动装配。Spring内部提供了指标门面(an application metrics facade)模式,该模式提供了对于众多监控系统的支持,包括:

提示

要了解更多关于Micrometer的功能,请参考它的参考文档,特别是概念部分

入门(Getting started)

Spring Boot自动装配了一个组合类型(composite)的指标注册表(MeterRegistry),对于在classpath下发现的任何指标注册表(MeterRegistery)的实现,Spring Boot会将其加入到这个组合类型的指标注册表中。实际上,在运行期(runtime)的classpath下增加micrometer-registry-{system}(笔者注:此处的system可以替换成上述列表中的监控系统)依赖后,Spring Boot就会自动配置对应类型的注册表(registery)。

大多数注册表都有相同的特性。例如,即使(Micrometer的)注册表的实现类在classpath内,也可以将其禁用。例如,要禁用Datadog:

1
2
3
4
5
management:
metrics:
export:
datadog:
enabled: false

也可以禁用所有注册表,除非某注册表已经通过自己的配置单独启用,如下例所示:

1
2
3
4
5
management:
metrics:
export:
defaults:
enabled: false

Spring Boot将自动装配的注册器添加到Metrics类(笔者注:全类限定名为:io.micrometer.core.instrument.Metrics)的全局静态组合注册表中,触发显示禁用:

1
2
3
management:
metrics:
use-global-registry: false

可以注册任意数量的类型为MeterRegistryCustomizer的bean,这些bean可以实现对注册表的自定义化配置,例如当任意指标注册到指标注册表中时,每个为这些指标增加通用的Tag标记:

1
2
3
4
5
6
7
8
@Configuration(proxyBeanMethods = false)
public class MyMeterRegistryConfiguration {

@Bean
public MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
return (registry) -> registry.config().commonTags("region", "us-east-1");
}
}

也可以通过更具体的泛型类型的支实现对特定注册表的自定义化配置:

1
2
3
4
5
6
7
8
9
10
11
12
@Configuration(proxyBeanMethods = false)
public class MyMeterRegistryConfiguration {

@Bean
public MeterRegistryCustomizer<GraphiteMeterRegistry> graphiteMetricsNamingConvention() {
return (registry) -> registry.config().namingConvention(this::name);
}

private String name(String name, Meter.Type type, String baseUnit) {
return ...
}
}

Spring Boot还内置的很多指标和仪表,可以通过配置文件或专用注解来控制这些指标。

支持的监控系统(Supported Monitoring Systems)

AppOptics

默认情况下,AppOptics注册表负责将指标周期性地推送到 api.appoptics.com/v1/measurements。为了把指标推送到Saas AppOptics平台,需要在配置里提供API令牌(API token):

1
2
3
4
5
6
management:
metrics:
export:
appoptics:
api-token: "YOUR_TOKEN"

Atlas

默认情况下, Atlas 指标暴露给本机正在运行的Atlas服务器。 Atlas服务器 的地址可以使用如下配置进行修改:

1
2
3
4
5
management:
metrics:
export:
atlas:
uri: "https://atlas.example.com:7101/api/v1/publish"

Datadog

Datadog注册表负责周期性地将指标推送给datadoghq。为了把指标推送到 Datadog,需要在配置里提供API秘钥(API key):

1
2
3
4
5
management:
metrics:
export:
datadog:
api-key: "YOUR_KEY"

Dynatrace

Dynatrace注册表负责将指标周期性地推送给配置的URL。为了把指标推送到Dynatrace,需要提供API令牌(API token)、设备ID(device ID)以及URL:

1
2
3
4
5
6
7
management:
metrics:
export:
dynatrace:
api-token: "YOUR_TOKEN"
device-id: "YOUR_DEVICE_ID"
uri: "YOUR_URI"

也可以修改推送指标到Dynatrace的间隔时间:

1
2
3
4
5
management:
metrics:
export:
dynatrace:
step: "30s"

Elastic

默认情况下,指标会被推送到本机运行的Elastic服务器上,而Elastic服务器的地址可以通过如下配置进行修改:

1
2
3
4
5
management:
metrics:
export:
elastic:
host: "https://elastic.example.com:8086"

Ganglia

默认情况下,指标会被推送到本机运行的Ganglia服务器上,Ganglia服务器的地址和端口可以通过如下配置进行修改:

1
2
3
4
5
6
management:
metrics:
export:
ganglia:
host: "ganglia.example.com"
port: 9649

Graphite

默认情况下,指标会被推送到本机运行的 Graphite服务器上, Graphite服务器的地址和端口可以通过如下配置进行修改:

1
2
3
4
5
6
management:
metrics:
export:
graphite:
host: "graphite.example.com"
port: 9004

Micrometer提供了一个默认的HierarchicalNameMapper,用于管理如何在多维度的指标名称扁平化指标名称之间进行映射转换

提示

如果想实现自定义的名称映射管理,需要自己实现GraphiteMeterRegistry并且提供自定义的HierarchicalNameMapperGraphiteConfigClock不需要自定义,它们会被Spring自动装配,除非用户已经自己定义。

1
2
3
4
5
6
7
8
9
10
11
12
@Configuration(proxyBeanMethods = false)
public class MyGraphiteConfiguration {

@Bean
public GraphiteMeterRegistry graphiteMeterRegistry(GraphiteConfig config, Clock clock) {
return new GraphiteMeterRegistry(config, clock, this::toHierarchicalName);
}

private String toHierarchicalName(Meter.Id id, NamingConvention convention) {
return ...
}
}

Humio

默认情况下,指标被周期性地推送到 cloud.humio.com,为了把指标推送到Saas Humio平台,需要提供API令牌(API token):

1
2
3
4
5
management:
metrics:
export:
humio:
api-token: "YOUR_TOKEN"

也可以为每个要推送的指标配置一个或多个Tag标记,用来区分数据源:

1
2
3
4
5
6
7
management:
metrics:
export:
humio:
tags:
alpha: "a"
bravo: "b"

Influx

默认情况下,指标被推送(exported)给运行于本机的v1版本的 Influx,如果想把指标推送给InfluxDB v2,需要配置orgbucket和认证用的tokenInflux服务器的地址可以通过如下配置进行修改:

1
2
3
4
5
management:
metrics:
export:
influx:
uri: "https://influx.example.com:8086"

JMX

Micrometer提供了向JMX的层级映射,主要用来当做一种低成本且便携的本地查看指标的方式。默认情况下,指标被推送给JMX的metrics作用域(domain),而作用域也可以通过如下配置进行修改:

1
2
3
4
5
management:
metrics:
export:
jmx:
domain: "com.example.app.metrics"

Micrometer提供了一个默认的HierarchicalNameMapper,用于管理如何在多维度的指标名称扁平化指标名称之间进行映射转换

提示

如果想实现自定义的名称映射管理,需要自己实现JmxMeterRegistry并且提供自定义的HierarchicalNameMapperJmxConfig Clock不需要自定义,它们都被Spring自动装配,除非用户已经自己定义。

1
2
3
4
5
6
7
8
9
10
11
12
13
>@Configuration(proxyBeanMethods = false)
>public class MyJmxConfiguration {

@Bean
public JmxMeterRegistry jmxMeterRegistry(JmxConfig config, Clock clock) {
return new JmxMeterRegistry(config, clock, this::toHierarchicalName);
}

private String toHierarchicalName(Meter.Id id, NamingConvention convention) {
return ...
}

>}

KairosDB

默认情况下,指标会被推送到本机运行的 KairosDB 服务器上, KairosDB 服务器的地址可以通过如下配置进行修改:

1
2
3
4
5
management:
metrics:
export:
kairos:
uri: "https://kairosdb.example.com:8080/api/v1/datapoints"

New Relic

New Relic注册表负责周期性地将指标推送给New Relic。为了把指标推送到 New Relic,需要在配置里提供API秘钥(API key)和账号id(account id):

1
2
3
4
5
6
management:
metrics:
export:
newrelic:
api-key: "YOUR_KEY"
account-id: "YOUR_ACCOUNT_ID"

也可以修改推送指标到New Relic的间隔时间:

1
2
3
4
5
management:
metrics:
export:
newrelic:
step: "30s"

默认情况下,指标以REST的形式推送。也可以使用Java Agent API,如果响应的类库在classpath路径内的情况下:

1
2
3
4
5
management:
metrics:
export:
newrelic:
client-provider-type: "insights-agent"

最后,也可以通过自定义实现NewRelicClientProvider bean获得完全的控制权。

Prometheus

Prometheus获取指标的方式是向应用程序拉取或轮询的指标数据。Spring Boot提供了一个可用的端点/actuator/prometheus,并以适当的方式提供给Prometheus指标采集器(Prometheus scrape)

提示

端点默认是禁用的,并且还需要开放暴露,可用查看暴露端点(Exposing Endpoints)获取更详细信息

以下是prometheus.yml配置文件中的scrape_config配置示例:

1
2
3
4
5
scrape_configs:
- job_name: 'spring'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['HOST:PORT']

对于某些无法被拉取的短暂任务或批量任务, Prometheus的Pushgateway组件提供了将指标推送给Prometheus的方式。如果要启用Pushgateway的支持,需要增加如下依赖:

1
2
3
4
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_pushgateway</artifactId>
</dependency>

当Pushgateway 组件存在于classpath下,并且management.metrics.export.prometheus.pushgateway.enabled被设置为true时,Spring Boot会自动装配一个PrometheusPushGatewayManager bean。这个bean就复杂将指标推送到Pushgateway

可以通过management.metrics.export.prometheus.pushgateway.属性对PrometheusPushGatewayManager进一步配置,当然,用户也可以自定义PrometheusPushGatewayManager bean。

SignalFx

SignalFx注册表负责周期性地将指标推送给 SignalFx。为了把指标推送到 SignalFx,需要在配置里提供访问令牌(access token):

1
2
3
4
5
management:
metrics:
export:
signalfx:
access-token: "YOUR_ACCESS_TOKEN"

也可以修改推送指标到SignalFx的间隔时间:

1
2
3
4
5
management:
metrics:
export:
signalfx:
step: "30s"

Simple

Micrometer内置了一个简易的、在内存中的(in-memory)注册表。如果其他的注册表都没有被配置,它会将当做默认的指标监控系统。通过该系统,可以在指标端点中查看系统收集了哪些指标。

只要启用了其他任意监控系统,simple系统就会被自动禁用。当然也可以显式将其关闭:

1
2
3
4
5
management:
metrics:
export:
simple:
enabled: false

Stackdriver

Stackdriver注册表负责周期性地将指标推送给Stackdriver。为了把指标推送到SaaS Stackdriver平台,需要在配置里提供谷歌云的project id:

1
2
3
4
5
management:
metrics:
export:
stackdriver:
project-id: "my-project"

也可以修改推送指标到Stackdriver的间隔时间:

1
2
3
4
5
management:
metrics:
export:
stackdriver:
step: "30s"

StatsD

StatsD注册表通过UDP将指标推送到StatsD代理。默认情况下,指标将被推送到本机运行的StatsD代理。StatsD代理的主机(host)、端口(port)和协议(协议)可以通过以下方式修改:

1
2
3
4
5
6
7
management:
metrics:
export:
statsd:
host: "statsd.example.com"
port: 9125
protocol: "udp"

也可以修改StatsD所使用的line协议(line protocol)(默认为Datadog):

1
2
3
4
5
management:
metrics:
export:
statsd:
flavor: "etsy"

Wavefront

Wavefront注册表负责周期性地将指标推送给Wavefront。为了把指标推送到Wavefront,需要在配置里提供API令牌(API token):

1
2
3
4
5
management:
metrics:
export:
wavefront:
api-token: "YOUR_API_TOKEN"

你可能会使用一个Wavefront边车代理(Wavefront sidecar)或设置一个内部代理,用于将指标数据转发到Wavefront API主机:

1
2
3
4
5
management:
metrics:
export:
wavefront:
uri: "proxy://localhost:2878"

指标

如果是将指标发布到Wavefront代理(如文档所述),主机的配置格式必须为:proxy://HOST:PORT

也可以修改推送指标到Wavefront的间隔时间:

1
2
3
4
5
management:
metrics:
export:
wavefront:
step: "30s"

支持的指标和仪表(Supported Metrics and Meters)

对于(系统使用的)各种的技术组件,Spring Boot都提供了指标自动注册。大多数情况下,这些开箱即用的指标注册表会选择适当的指标,并将其发布到任意所支持的监控系统上。

JVM指标(JVM Metrics)

自动装配机制会使用Micrometer的核心代码开启JVM指标。JVM指标被发布在jvm.名称下。如下JVM指标都是支持的:

  • 各种内存和缓冲池详细信息
  • 垃圾收集相关统计
  • 线程利用率
  • 被加载/卸载的class数量

系统指标(System Metrics)

自动装配机制会使用Micrometer的核心代码开启系统指标。系统指标被发布在system.process.名称下。如下系统指标都是支持的:

  • CPU指标
  • 文件指标(File descriptor metrics)
  • 运行时间指标(包括系统的运行时间以及启动时的绝对时间)

日志指标(Logger Metrics)

自动装配机制支持Logback和Log4J2的日志事件。这些指标被发布在log4j2.events.logback.events.下面。

Spring MVC指标( Spring MVC Metrics)

自动装配机制会开启对 Spring MVC控制器(Spring MVC controllers)和请求处理器(functional handlers)的所有请求的采集。默认情况下,指标的名称前缀为 http.server.requests。可以通过设置 management.metrics.web.server.request.metric-name 来自定义该前缀。

@Controller类和@RequestMapping方法支持@Timed注解(详情参考:[@Timed注解支持(@Timed Annotation Support)](##@Timed注解支持(@Timed Annotation Support)))。如果不想开启所有的Spring MVC请求,可以将management.metrics.web.server.request.autotime.enabled设置为false,而仅使用@Timed注解。

默认情况下,Spring MVC相关的指标会被增加如下tag标记:

Tag 详情
exception 当处理请求出现异常时,被抛出的异常类的简短类名
method 请求方法(例如:GETPOST
outcome 基于响应状态码的返回值描述,1xx:INFORMATIONAL;2xx:SUCCESS;3xx:REDIRECTION;4xx:CLIENT_ERROR;5xx:SERVER_ERROR
status 响应状态码(例如200500
url 在变量替换之前使用请求的URI模板(例如,/api/person/{id})

如果想添加默认的tag标记,可以提供一个或多个实现了WebMvcTagsContributor@Bean,如果想替换(上述)tag标记,提供一个实现了WebMvcTagsProvider@Bean

提示

在某些情况下,控制器和请求处理器内处理的异常并不会以指标tag标记的方式(如上表)被记录。此时,应用程序可以通过将异常设置为请求的属性来确保该异常处理不会被遗漏。

Spring WebFlux指标(Spring WebFlux Metrics)

自动装配机制会开启对 Spring WebFlux控制器(Spring WebFlux controllers)和请求处理器(functional handlers)的所有请求的采集。默认情况下,指标的名称前缀为 http.server.requests。可以通过设置 management.metrics.web.server.request.metric-name 来自定义该前缀。

@Controller类和@RequestMapping方法支持@Timed注解(详情参考:[@Timed注解支持(@Timed Annotation Support)](##@Timed注解支持(@Timed Annotation Support)))。如果不想开启所有的Spring WebFlux请求,可以将management.metrics.web.server.request.autotime.enabled设置为false,而仅使用@Timed注解。

默认情况下,Spring WebFlux相关的指标会被增加如下tag标记:

Tag 详情
exception 当处理请求出现异常时,被抛出的异常类的简短类名
method 请求方法(例如:GETPOST
outcome 基于响应状态码的返回值描述,1xx:INFORMATIONAL;2xx:SUCCESS;3xx:REDIRECTION;4xx:CLIENT_ERROR;5xx:SERVER_ERROR
status 响应状态码(例如200500
url 在变量替换之前使用请求的URI模板(例如,/api/person/{id})

如果想添加默认的tag标记,可以提供一个或多个实现了WebFluxTagsContributor@Bean,如果想替换(上述)tag标记,提供一个实现了WebFluxTagsProvider@Bean

提示

在某些情况下,控制器和请求处理器内处理的异常并不会以指标tag标记的方式(如上表)被记录。此时,应用程序可以通过将异常设置为请求的属性来确保该异常处理不会被遗漏。

Jersey Server指标(Jersey Server Metrics)

只要Micrometer的micrometer-jersey2模块在classpath下,自动装配机制会开启所有由Jersey JAX-RS实现的请求。默认情况下,指标的名称前缀为 http.server.requests。可以通过设置 management.metrics.web.server.request.metric-name 来自定义该前缀。

默认情况下,Jersey server相关的指标会被增加如下tag标记:

Tag 详情
exception 当处理请求出现异常时,被抛出的异常类的简短类名
method 请求方法(例如:GETPOST
outcome 基于响应状态码的描述,1xx:INFORMATIONAL;2xx:SUCCESS;3xx:REDIRECTION;4xx:CLIENT_ERROR;5xx:SERVER_ERROR
status 响应状态码(例如200500
url 在变量替换之前使用请求的URI模板(例如,/api/person/{id})

如果想自定义这些tag标记,提供一个实现了JerseyTagsProvider接口的@Bean即可

HTTP Client指标(HTTP Client Metrics)

Spring Boot Actuator提供了对RestTemplateWebClient的监测管理。不过使用需要通过注入自动装配的builder来创建实例:

  • 通过RestTemplateBuilder创建RestTemplate
  • 通过WebClient.Builder创建WebClient

也可以使用自定义的MetricsRestTemplateCustomizerMetricsWebClientCustomizer实现同相同目的。

默认情况下,指标的名称前缀为 http.client.requests,可以通过修改management.metrics.web.client.request.metric-name来自定义该前缀

默认情况下,相关指标会增加如下tag标记:

Tag 详情
clientName URI的主机地址
method 请求方法(例如:GETPOST
outcome 基于响应状态码的返回值描述,1xx:INFORMATIONAL;2xx:SUCCESS;3xx:REDIRECTION;4xx:CLIENT_ERROR;5xx:SERVER_ERROR
status 正常情况下为HTTP响应状态码(例如200500),出现I/O异常时为IO_ERROR,其他情况为CLIENT_ERROR
url 在变量替换之前使用请求的URI模板(例如,/api/person/{id})

可以提供一个实现了RestTemplateExchangeTagsProviderWebClientExchangeTagsProvider接口的@Bean,实现对tag标记的自定义。RestTemplateExchangeTags and WebClientExchangeTags内也包含方便使用的静态函数。

Tomcat指标( Tomcat Metrics)

MBeanRegistry注册表被启用时,自动装配机制会开启对Tomcat的监测。默认情况下,MBeanRegistry是关闭的,可以通过将server.tomcat.mbeanregistry.enabled设置为true来开启。

Tomcat指标以tomcat.为前缀。

缓存指标(Cache Metrics)

当应用启动时,自动装配机制会开启所有已生效Caches的监测,并以cache.为前缀。这是基础监测指标的标准化配置(Cache instrumentation is standardized for a basic set of metrics.)。此外,某些缓存专属指标也是生效的。如下缓存库已经被支持:

  • Caffeine
  • EhCache 2
  • Hazelcast
  • Any compliant JCache (JSR-107) implementation
  • Redis

这些指标会被附加两个tag标记,它们分别是以缓存命名的tag,以及实现了CacheManager的bean的名字。

提示

只有启动时被配置的缓存会被绑定到指标注册表中。对于那些没有在配置中定义的缓存,例如当启动后,实时地或编程方式创建的缓存,则需要显示地进行注册。CacheMetricsRegistrar bean提供了简单易用的注册机制。

数据源指标(DataSource Metrics)

自动装配会启用对所有可用DataSource对象的监测,这些指标以jdbc.connections为前缀。数据源测量结果以gauges的方式显示连接池内当前活动连接数、空闲连接数、最大连接数和最小连接数。

这些指标也会被附加tag标记,这些tag标记的名字就是DataSource bean的名字。

提示

默认情况下,对于所有支持的数据源,Spring Boot都提供了元数据(metadata)。如果使用的数据源不支持这个开箱即用的特性,可以额外提供DataSourcePoolMetadataProvider,可以到DataSourcePoolMetadataProvidersConfiguration查看使用示例。

Hibernate指标( Hibernate Metrics)

如果org.hibernate:hibernate-micrometer在classpath内,所有生效且开启统计EntityManagerFactory实例都会被监测,指标名为:hibernate

这些指标也会被附加tag标记,tag标记的名字就是EntityManagerFactory bean的名字。

如果要开启统计功能,JPA属性hibernate.generate_statistics必须要被设置为true,可以通过如下示例将EntityManagerFactory开启:

1
2
3
4
spring:
jpa:
properties:
"[hibernate.generate_statistics]": true

Spring Data Repository指标(Spring Data Repository Metrics)

自动装配机制会开启Spring Data Repository的所有函数调用的监测。默认情况下,指标名为spring.data.repository.invocations,可以通过management.metrics.data.repository.metric-name对其修改。

Repository类及其方法支持@Timed(查看@Timed注解支持了解更多细节)注解。如果不想对所有的Repository调用都开启指标监控,可以将management.metrics.data.repository.autotime.enabled设置为false,并且单独使用@Timed

默认情况下,Repository相关的指标会被附加如下tag标记:

Tag 详情
repository Repository的简单类名
method 被调用的Repository方法名
state 状态(SUCCESS, ERROR, CANCELED or RUNNING
exception 当调用出现异常时,异常类的简单类名

如果想修改这些默认的tag标记,配置一个实现了RepositoryTagsProvider接口的@Bean

RabbitMQ指标(RabbitMQ Metrics)

自动装配机制会开启所有可用的RabbitMQ 连接的监控,指标名为rabbitmq

Spring Integration指标(Spring Integration Metrics)

任何时候,当MeterRegistry bean可用时,Spring Integration会自动提供基于Micrometer的监测支持。并且指标会被发布在spring.integration.下面。

Kafka指标(Kafka Metrics)

自动装配机制会分别为自动装配的消费者工厂(consumer factory)和生产者工厂(producer factory)注册一个 MicrometerConsumerListenerMicrometerProducerListener。也会为StreamsBuilderFactoryBean注册一个KafkaStreamsMicrometerListener。更多详情,请参考Spring Kafka文档的 Micrometer原生指标

MongoDB指标(MongoDB Metrics)

命令指标(Command Metrics)

自动装配机制会为自动装配的MongoClient注册一个MongoMetricsCommandListener

对于mongoDB driver下的每一条指令,都会创建一个名为mongodb.driver.commands的计时器指标(timer metric)。每个指标默认会附加如下tag标记:

Tag 详情
command 命令的名称
cluster.id 执行命令的monoDB集群的id
server.address 执行命令的mongoDB的的服务器地址
status 命令返回结果(SUCCESSFAILED中的一个)

如果想替换默认的指标tag标记,可以定义一个MongoCommandTagsProvider bean,如下所示:

1
2
3
4
5
6
7
8
@Configuration(proxyBeanMethods = false)
public class MyCommandTagsProviderConfiguration {

@Bean
public MongoCommandTagsProvider customCommandTagsProvider() {
return new CustomCommandTagsProvider();
}
}

如果想禁用上述命令指标,可以按照如下指令进行设置:

1
2
3
4
5
management:
metrics:
mongo:
command:
enabled: false

连接池指标(Connection Pool Metrics)

自动装配机制会为自动装配的MongoClient注册一个MongoMetricsConnectionPoolListener

连接池会创建如下gauge指标:

  • mongodb.driver.pool.size上报当前连接池内的连接数量,包括空闲和使用者的连接。
  • mongodb.driver.pool.checkedout上报连接池内正在使用的连接数量
  • mongodb.driver.pool.waitqueuesize上报连接池等待队列的大小

默认情况下,每个指标都会被附加如下tag标记:

Tag 详情
cluster.id 当前连接池对应的monoDB集群的id
server.address 当前连接池对应的monoDB集群的服务器地址

如果想替换默认的指标tag标记,可以定义一个MongoConnectionPoolTagsProvider bean,如下所示:

1
2
3
4
5
6
7
8
@Configuration(proxyBeanMethods = false)
public class MyConnectionPoolTagsProviderConfiguration {

@Bean
public MongoConnectionPoolTagsProvider customConnectionPoolTagsProvider() {
return new CustomConnectionPoolTagsProvider();
}
}

如果想禁用上述连接池指标,可以按照如下指令进行设置:

1
2
3
4
5
management:
metrics:
mongo:
connectionpool:
enabled: false

@Timed注解支持(@Timed Annotation Support)

io.micrometer.core.annotation包内的@Timed注解可以被上述列出的某些指标支持。一旦被支持,这个注解既可以用在类层级,也可以用在函数层级上。

例如,如下代码展示了这个注解如何监测@RestController类的所有请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController
@Timed
public class MyController {

@GetMapping("/api/addresses")
public List<Address> listAddress() {
return ...
}

@GetMapping("/api/people")
public List<Person> listPeople() {
return ...
}
}

如果只想监测某一个请求,可以将注解从类层级移到方法层级上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController
public class MyController {

@GetMapping("/api/addresses")
public List<Address> listAddress() {
return ...
}

@GetMapping("/api/people")
@Timed
public List<Person> listPeople() {
return ...
}
}

如果想修改方法层级的指标信息,可以对该注解组合使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@RestController
@Timed
public class MyController {

@GetMapping("/api/addresses")
public List<Address> listAddress() {
return ...
}

@GetMapping("/api/people")
@Timed(extraTags = { "region", "us-east-1" })
@Timed(value = "all.people", longTask = true)
public List<Person> listPeople() {
return ...
}
}

提示

带有longTask = true@Timed注解为方法启用一个长时间任务计时器指标(long task timer)。该指标需要单独的名称,并且可以与短时间任务计时器指标进行叠加。(译者注:此处没有说明叠加内容,如何叠加,需要后续进一步研究)

注册自定义指标(Registering Custom Metrics)

如果想注册自定义指标,可以将MeterRegistry注入到自己的组件中,如下面例子所示:

1
2
3
4
5
6
7
8
9
10
@Component
public class MyBean {

private final Dictionary dictionary;

public MyBean(MeterRegistry registry) {
this.dictionary = Dictionary.load();
registry.gauge("dictionary.size", Tags.empty(), this.dictionary.getWords().size());
}
}

如果要注册的指标需要依赖其他bean,建议使用MeterBinder来注册,如下面的例子所示:

1
2
3
4
5
6
7
public class MyMeterBinderConfiguration {

@Bean
public MeterBinder queueSize(Queue queue) {
return (registry) -> Gauge.builder("queueSize", queue::size).register(registry);
}
}

使用MeterBinder可以确保依赖的正确性,并且在指标被检索时,这个bean是可用的。如果经常重复性跨组件或应用监测一组指标,MeterBinder会非常有用。

提示

默认情况下,所有的MeterBinder bean会自动绑定到由Spring管理的MeterRegistery中。

自定义特定指标(Customizing Individual Metrics)

如果想对特定的Meter实例进行自定义,可用使用io.micrometer.core.instrument.config.MeterFilte接口。

例如,如果想对所有以com.example开头的指标进行自定义:将mytag.region改为mytag.area,可用按照如下示例操作:

1
2
3
4
5
6
7
8
@Configuration(proxyBeanMethods = false)
public class MyMetricsFilterConfiguration {

@Bean
public MeterFilter renameRegionTagMeterFilter() {
return MeterFilter.renameTag("com.example", "mytag.region", "mytag.area");
}
}

提示

默认情况下,所有MeterFilter bean会自动绑定到由Spring管理的MeterRegistery中。要确保将自定义指标注册到由Spring管理的MeterRegistery上,并且在Metrics中不能含有静态函数。而全局的注册表并没有被Spring管理!

自定义通用Tag标记(Common Tags)

通用Tag标记常用来对诸如主机名(host)、实例名(instance)、地区(region)、集群(stack)等操作环境进行更细粒度的划分。通用Tag标记会被附加到所有的指标上,可以按照如下示例进行配置:

1
2
3
4
5
management:
metrics:
tags:
region: "us-east-1"
stack: "prod"

以上示例中,会分别为每个指标增加两个tag标记:region:us-east-1stack:prod

提示

如果使用Graphite,通用tag标记的顺序非常重要。因为这个方式并不能保证通用tag标记的的属性,Graphite用户请使用MeterFilter的方式。

精确指标配置(Per-meter Properties)

除了MeterFilter之外,也可以通过配置对每一个指标进行调整。可以在配置中指定指标的名称,所有以该名称为前缀的指标都会被调整。下面示例中,所有以example.remote开头的指标都会被禁用:

1
2
3
4
5
management:
metrics:
enable:
example:
remote: false

如下配置都可以应用到指标的调整:

属性 详情
management.metrics.enable 是否禁止指标
management.metrics.distribution.percentiles-histogram 是否使用于百分比直方图(Whether to publish a histogram suitable for computing aggregable (across dimension) percentile approximations.)
management.metrics.distribution.minimum-expected-value, management.metrics.distribution.maximum-expected-value 通过设置监测有效范围可以减少直方图中桶的数量(Publish less histogram buckets by clamping the range of expected values.)
management.metrics.distribution.percentiles 需要被统计的百分位数(Publish percentile values computed in your application)
management.metrics.distribution.slo 额外自定义的应用级的直方图(Publish a cumulative histogram with buckets defined by your service-level objectives)

译者提示

  • 关于上述配置可以参考IBM developerWorks的一篇文章《使用 Micrometer 记录 Java 应用性能指标》(可惜网站已经关闭,该链接为github的备份)
  • management.metrics.enable是一个map,key为指标ID前缀(最长的优先匹配),value为Boolean
  • management.metrics.distribution.percentiles 代表要统计的百分位数,这是一个map,key为指标ID前缀(最长的优先匹配),value为double型且取值区间为[0,1]的数组,代表某指标要统计的百分位数。百分位数是统计学指标,详情可以参考wikipedia词条
  • management.metrics.distribution.slo 针对的是整个应用,而无法针对某一个指标进行单独配置

更多关于percentiles-histogrampercentiles的详情,可以参考micrometer文档的 “直方图和百分位数”

指标端点(Metrics Endpoint)

Spring Boot提供了一个metrics端点,作为诊断性的目的,可以用来检查应用程序收集到的指标。这个端点默认没有被暴露出来,可以查看暴露端点(Exposing Endpoints)获得更多细节。

/actuator/metrics列出了所有可用的端点的名称,可以通过指定某指标的名称进一步查看更详细信息,例如:/actuator/metrics/jvm.memory.max

提示

此处使用的指标名称应该和代码中的名字相匹配,而不是将指标名称进行映射转换后,特定监控系统的指标名称。例如,Prometheus使用的是蛇形命名法,jvm.memory.max会被映射转换成jvm_memory_max。此时,在metrics端点中,仍然应该使用jvm.memory.max

可以在查询语句上增加任意数量的查询参数:tag=KEY:VALUE,从而获得某一维度上的详细指标,例如:/actuator/metrics/jvm.memory.max?tag=area:nonheap

提示

measurements字段是某个指标下所有tag的统计数据的总和,在上面的例子中,这个数据是堆内存中“Code Cache”、“Compressed Class Space”和“Metaspace”各自最大值的总和,如果只想查看“Metaspace”的的最大值,可用在查询语句上增加额外的tag标记:tag=id:Metaspace,例如:/actuator/metrics/jvm.memory.max?tag=area:nonheap&tag=id:Metaspace

审计(Auditing)

一旦Spring Security被启用,Spring Boot Actuator就有了一个灵活的审计框架可以发布事件(默认情况下,包括“认证成功”(authentication success)、“失败”(failure)和“拒绝访问”(access denied)的异常)。该特性对于报告和实现基于身份验证失败的锁定策略非常有用。

可以通过定义一个AuditEventRepository类型的bean开启审计功能。为了方便用户,Spring Boot内置了一个InMemoryAuditEventRepository。不过它的能力有限,我们建议只在开发环境下使用。至于生产环境,需要创建自己的AuditEventRepository

自定义审计(Custom Auditing)

如果想自定义安全事件,可以提供自定义的AbstractAuthenticationAuditListenerAbstractAuthorizationAuditListener的实现。

您还可以对自己的业务事件使用审计服务。要做到这一点,可以将AuditEventRepository bean注入到自己的组件中并直接使用它,或者使用Spring ApplicationEventPublisher(实现ApplicationEventPublisherAware接口)发布一个AuditApplicationEvent

HTTP追踪(HTTP Tracing)

可以在应用中提供一个HttpTraceRepository类型的bean开启HTTP追踪功能。为了方便用户,Spring Boot内置了一个InMemoryHttpTraceRepository 用于存储最近100条请求和响应。相比于其他最终方案,默认提供的InMemoryHttpTraceRepository功能有限,我们建议仅在开发环境下使用。对于生产环境,请使用具备生产就绪特性的追踪、观测方案。例如ZipKin或Spring Cloud Sleuth。此外,也可以提供一个自定义的HttpTraceRepository满足业务需求。

httptrace端点可以用来获取存储在HttpTraceRepository中的请求响应的信息。

自定义HTTP追踪(Custom HTTP tracing)

如果想自定义追踪数据,使用management.trace.http.include。对于更加深入的自定义,可以考虑注册自定义实现的HttpExchangeTracer bean。

进程监控(Process Monitoring)

在Spring Boot中,有两个类可以用来创建文件,这在监控进程时非常有用:

  • ApplicationPidFileWriter 可以创建一个包含应用PID的文件(默认情况下,文件位于应用目录,文件名为:application.pid
  • WebServerPortFileWriter创建一个(或多个)包含当前web服务器的端口的文件

这两个类默认是没有被激活,可以通过如下方式将其开启:

扩展配置(Extending Configuration)

META-INF/spring.factories中,你可以通过如下方式激活一个或多个监听,从而实现PID文件的写入:

1
2
3
org.springframework.context.ApplicationListener=\
org.springframework.boot.context.ApplicationPidFileWriter,\
org.springframework.boot.web.context.WebServerPortFileWriter

编程方式支持(Programmatically)

也可以通过调用SpringApplication.addListeners(…)来激活一个监听器,并传入一个Writer对象,这种方式允许你在Writer的构造函数中自定义文件名、文件路径。

Cloud Foundry 支持(Cloud Foundry Support)

Spring Boot Actuator对Cloud Foundry提供了额外支持,当应用被部署到兼容的Cloud Foundry实例时,该特性会被激活。/cloudfoundryapplication提供了另外一种到所有端点@Endpoint bean安全路由。

提示

对于常规用户来说,/cloudfoundryapplication路径不能被直接访问。如果想使用该端点,需要在请求中提供一个UAA令牌(UAA token)。

禁用Cloud Foundry Actuator支持(Disabling Extended Cloud Foundry Actuator Support)

如果想完全禁用/cloudfoundryapplication端点,可以进行如下配置:

1
2
3
management:
cloudfoundry:
enabled: false

Cloud Foundry自签名证书(Cloud Foundry Self-signed Certificates)

默认情况下,/cloudfoundry端点的安全认证会对Cloud Foundry服务进行SSL调用。如果您的Cloud Foundry UAA或Cloud Controller服务使用自签名证书,您需要设置以下属性:

1
2
3
management:
cloudfoundry:
skip-ssl-validation: true

自定义上下文路径(Custom Context Path)

如果服务器的上下文路径并非/,而是其他路径,那么根路径下的Cloud Foundry端点会不可用。例如,对于配置server.servlet.context-path=/app,Cloud Foundry端点路径为:/app/cloudfoundryapplication/*

如果想实现这个需求:不管服务器的上下文路径如何配置, Cloud Foundry端点的路径都位于:/cloudfoundryapplication/*,需要在应用中进行配置,至于配置方式,根据所使用的web服务器的不同而不尽相同。以Tomcat为例,可以使用如下配置:

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
28
29
30
31
32
33
34
35
36
37
38
@Configuration(proxyBeanMethods = false)
public class MyCloudFoundryConfiguration {

@Bean
public TomcatServletWebServerFactory servletWebServerFactory() {
return new TomcatServletWebServerFactory() {

@Override
protected void prepareContext(Host host, ServletContextInitializer[] initializers) {
super.prepareContext(host, initializers);
StandardContext child = new StandardContext();
child.addLifecycleListener(new Tomcat.FixContextListener());
child.setPath("/cloudfoundryapplication");
ServletContainerInitializer initializer = getServletContextInitializer(getContextPath());
child.addServletContainerInitializer(initializer, Collections.emptySet());
child.setCrossContext(true);
host.addChild(child);
}

};
}

private ServletContainerInitializer getServletContextInitializer(String contextPath) {
return (classes, context) -> {
Servlet servlet = new GenericServlet() {

@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
ServletContext context = req.getServletContext().getContext(contextPath);
context.getRequestDispatcher("/cloudfoundryapplication").forward(req, res);
}

};
context.addServlet("cloudfoundry", servlet).addMapping("/*");
};
}

}

接下来要读什么(What to Read Next)

你可能想读一些关于图形工具的文档,例如Graphite](https://graphiteapp.org/)

或者,如果想继续深挖,可以阅读部署选项相关知识,或者提前了解有关Spring Boot构建工具插件的知识。