Part V. Spring Boot Actuator: Production-ready features
文档说明:
- 文档对应的版本为 2.1.0.M3
- 这不是文档的完整中文翻译,也有可能跟原文文字不一一对应,只是我阅读文档时候做的简单笔记
- 如果对应的章节没有任何中文,有可能是文档内容比较少,建议直接看原文,或者是我不感兴趣的部分
- 目录标题没有做翻译,首先标题一般一眼就能看懂什么意思,不做翻译还能保证原文意思,其次也方便对应到原文位置
Spring Boot 很多特性来帮助你监控和管理应用。当发布到生产,你可以选择通过 HTTP endpoints 或者 JMX 来管理和监控你的应用。安全审计,健康检查和统计收集在你的应用都可以使用。
51. Enabling Production-ready Features
spring-boot-actuator 模块提供了所有 Spring Boot’s production-ready features。
Actuator 的定义:它是行业术语,指的是一个用来移动和控制某些东西的机械设备。
添加 starter
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
52. Endpoints
Actuator endpoints 让你的监控和应用做交互。Spring Boot 提供了很多内建的 endpoints,并允许你创建自己的 endpoints。例如 health endpoints 提供了应用的基本健康信息。
每个 endpoint 都可以设置启动或者禁用。为了可以远程访问,endpoint 可以通过 JMX 或者 HTTP 暴露接口出来。大部分应用都选择了 HTTP,endpoint 的 ID 都会带有 /actuator 前缀。例如 health endpoint 的映射就是 /actuator/health。
technology-agnostic endpoints table
Spring Boot Actuator Web API Documentation
52.1 Enabling Endpoints
默除了 shutdown 之外的所有 endpoints 默认都会启用,可通过 management.endpoint.<id>.enabled 属性来配置,例如启用 shutdow endpoints
management.endpoint.shutdown.enabled=true
如果只想启用某几个 endpoints,可以先禁用所有的 endpoints,再单独启用指定的 endpoints,例如只启用 info endpoint:
management.endpoints.enabled-by-default=false
management.endpoint.info.enabled=true
52.2 Exposing Endpoints
endpoints 可能包含敏感信息,所以暴露对应的接口时需小心谨慎。
the default exposure for the built-in endpoints table
通过 include 和 exclude 的属性可以配置 endpoints 的接口是否暴露出来,还可以支持通配符
management.endpoints.web.exposure.include=*
management.endpoints.web.exposure.exclude=env,beans
52.3 Securing HTTP Endpoints
如果你只允许某种角色的用户才可以访问 endpoints,可通过 Spring Security 来实现。例如:
@Configuration
public class ActuatorSecurity extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests()
.anyRequest().hasRole("ENDPOINT_ADMIN")
.and()
.httpBasic();
}
}
上面例子通过 EndpointRequest.toAnyEndpoint() 来匹配所有的 endpoints 的请求。
如果你部署的应用有防火墙控制,那么可以不在应用做安全控制。
52.4 Configuring Endpoints
Endpoints 会自动缓存那些不需要任何参数的读操作请求的响应内容,我们可以配置它的缓存有效时间
management.endpoint.beans.cache.time-to-live=10s
如果是带有认证信息的 HTTP 请求,认证信息会认为是输入参数,所以所有响应内容都不会缓存。
52.5 Hypermedia for Actuator Web Endpoints
增加了 "discovery page" 来连接到所有的 endpoints,一般是 /actuator
52.6 CORS Support
跨域默认是不启用的,配置项如下:
management.endpoints.web.cors.allowed-origins=http://example.com
management.endpoints.web.cors.allowed-methods=GET,POST
52.7 Implementing Custom Endpoints
52.7.1 Receiving Input
52.7.2 Custom Web Endpoints
@Endpoint, @WebEndpoint, @EndpointWebExtension 都会通过 HTTP 自动被开放出来接口,HHTP 服务可以是 Jersey,Spring MVC 或者 Spring WebFlux。
Web Endpoint Request Predicates
为 Web 暴露的 endpoints 上的每个操作会自动生成请求谓词。
Path
The default base path is /actuator.
/actuator/endpoint_id
可通过 @Selector 来定制
HTTP method
Operation | HTTP method |
---|---|
@ReadOperation | GET |
@WriteOperation | POST |
@DeleteOperation | DELETE |
Consumes
@WriteOperation ==> application/vnd.spring-boot.actuator.v2+json, application/json
others ==> empty
Produces
Web Endpoint Response Status
@ReadOperation: 200 / 404
@WriteOperation / @DeleteOperation: 200 / 204
Web Endpoint Range Requests
An HTTP range request can be used to request part of an HTTP resource.
Web Endpoint Security
52.7.3 Servlet endpoints
一个 Servlet 可以通过 @ServletEndpoint 来实现 endpoint。
52.7.4 Controller endpoints
@ControllerEndpoint and @RestControllerEndpoint
52.8 Health Information
配置项 management.endpoint.health.show-details 控制了 /health endpoint 可以展示的信息,这个配置项的值可以是 never / when-authorized / always。
应用健康信息是从 HealthIndicatorRegistry 类(默认所有的 HealthIndicator 实例都会注册到 ApplicationContex)收集的。
52.8.1 Auto-configured HealthIndicators
自动装配的 HealthIndicators 有:
- CassandraHealthIndicator
- DiskSpaceHealthIndicator
- DataSourceHealthIndicator
- ElasticsearchHealthIndicator
- InfluxDbHealthIndicator
- JmsHealthIndicator
- MailHealthIndicator
- MongoHealthIndicator
- Neo4jHealthIndicator
- RabbitHealthIndicator
- RedisHealthIndicator
- SolrHealthIndicator
可通过 management.health.defaults.enabled 配置项来禁用
52.8.2 Writing Custom HealthIndicators
实现 HealthIndicator 接口
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;
@Component
public class MyHealthIndicator 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();
}
}
HealthIndicator 的 ID 属性是根据 bean 的名称然后减去 "HealthIndicator" 后缀,上面例子的 bean 名称为 myHealthIndicator,所以其 ID 值为 my。
添加自定义的状态类型。
例如添加新的状态类型 FATAL
management.health.status.order=FATAL, DOWN, OUT_OF_SERVICE, UNKNOWN, UP
management.health.status.http-mapping.FATAL=503
HTTP 状态码可以映射到这节讨论的状态类型,更多信息可参看 HealthStatusHttpMapper 类。
52.8.3 Reactive Health Indicators
实现 ReactiveHealthIndicator 接口
@Component
public class MyReactiveHealthIndicator implements ReactiveHealthIndicator {
@Override
public Mono<Health> health() {
//perform some specific health check that returns a Mono<Health>
return doHealthCheck()
.onErrorResume(ex -> Mono.just(new Health.Builder().down(ex).build())));
}
}
抽象类 AbstractReactiveHealthIndicator 提供了处理错误的默认实现。
52.8.4 Auto-configured ReactiveHealthIndicators
自动装配的 ReactiveHealthIndicators 有:
- CassandraReactiveHealthIndicator
- MongoReactiveHealthIndicator
- RedisReactiveHealthIndicator
52.9 Application Information
应用信息是从所有注入到 ApplicationContex 的 InfoContributor bean 收集的,你也可以实现自己的 InfoContributor。
52.9.1 Auto-configured InfoContributors
自动装配的 InfoContributors 有:
- EnvironmentInfoContributor
- GitInfoContributor
- BuildInfoContributor
通过 management.info.defaults.enabled 配置项可禁用
52.9.2 Custom Application Information
通过 info.* 配置项可以定制 info endpoint 展示的信息:
info.app.encoding=UTF-8
info.app.java.source=1.8
info.app.java.target=1.8
52.9.3 Git Commit Information
info endpoint 还可以展示你 git 代码的状态信息。
GitProperties
52.9.4 Build Information
BuildProperties 和 META-INF/build-info.properties
52.9.5 Writing Custom InfoContributors
实现 InfoContributor 接口
import java.util.Collections;
import org.springframework.boot.actuate.info.Info;
import org.springframework.boot.actuate.info.InfoContributor;
import org.springframework.stereotype.Component;
@Component
public class ExampleInfoContributor implements InfoContributor {
@Override
public void contribute(Info.Builder builder) {
builder.withDetail("example",
Collections.singletonMap("key", "value"));
}
}
53. Monitoring and Management over HTTP
53.1 Customizing the Management Endpoint Paths
/actuator/{id} ==> /manage/{id}
management.endpoints.web.base-path=/manage
/actuator/health ==> /healthcheck
management.endpoints.web.base-path=/
management.endpoints.web.path-mapping.health=healthcheck
53.2 Customizing the Management Server Port
management.server.port=8081
53.3 Configuring Management-specific SSL
配置了自定义的端口,Management 服务还可以被配置成自己的 SSL,通过 management.server.ssl.* 属性。
server.port=8443
server.ssl.enabled=true
server.ssl.key-store=classpath:store.jks
server.ssl.key-password=secret
management.server.port=8080
management.server.ssl.enabled=false
53.4 Customizing the Management Server Address
如果想配置允许 localhost 的请求:
management.server.port=8081
management.server.address=127.0.0.1
53.5 Disabling HTTP Endpoints
management.server.port=-1
# or
management.endpoints.web.exposure.exclude=*
54. Monitoring and Management over JMX
54.1 Customizing MBean Names
MBean 的名称通常是由 endpoint 的 id 来生成的,例如 health endpoint 的的接口为
org.springframework.boot:type=Endpoint,name=Health
如果你的应用包含多个 ApplicationContex,MBean 的名称可能会有冲突的场景。设置 spring.jmx.unique-names 属性为 true 可以应用这种场景。
还可以配置 JMX 的 domain
spring.jmx.unique-names=true
management.endpoints.jmx.domain=com.example.myapp
54.2 Disabling JMX Endpoints
management.endpoints.jmx.exposure.exclude=*
54.3 Using Jolokia for JMX over HTTP
Online: Jolokia 是一个用来访问远程 JMX MBeans 的崭新方法,与 JSR-160 连接器不同的是,它使用基于 HTTP 的 JSON 格式作为通讯协议,提供 JMX 批量操作等。
添加对应依赖
<dependency>
<groupId>org.jolokia</groupId>
<artifactId>jolokia-core</artifactId>
</dependency>
Customizing Jolokia
配置项: management.endpoint.jolokia.config.*
Disabling Jolokia
management.endpoint.jolokia.enabled=false
55. Loggers
Spring Boot Actuator 有查看和配置你应用在运行时的日志级别的能力。日记级别有:
- TRACE
- DEBUG
- INFO
- WARN
- ERROR
- FATAL
- OFF
- null
null 表明没有显示的配置。
55.1 Configure a Logger
POST 一个请求来配置日记级别:
{
"configuredLevel": "DEBUG"
}
重置日记级别可以 POST null 值过去。
56. Metrics
Spring Boot Actuator 提供了 Micrometer 的依赖管理和自动装配,Micrometer 是支持大量监控系统的应用监控门面,包括:
- Atlas
- Datadog
- Ganglia
- Graphite
- Influx
- JMX
- New Relic
- Prometheus
- SignalFx
- Simple (in-memory)
56.1 Getting started
禁用一个指定的 registry,例如禁用 Datadog:
# 禁用一个指定的 registry
management.metrics.export.datadog.enabled=false
# 禁用所有 registry 的自动装配
management.metrics.use-global-registry=false
56.2 Supported monitoring systems
56.2.1 Atlas
Metrics 默认使用 Atlas 来运行,配置 Atlas 服务地址:
management.metrics.export.atlas.uri=http://atlas.example.com:7101/api/v1/publish
56.2.2 Datadog
Datadog registry 会定时推送数据到 datadoghq,需要显示配置 Datadog 的 API key
management.metrics.export.datadog.api-key=YOUR_KEY
# 修改推送时间的间隔
management.metrics.export.datadog.step=30s
56.2.3 Ganglia
By default, metrics are exported to Ganglia running on your local machine.
management.metrics.export.ganglia.host=ganglia.example.com
management.metrics.export.ganglia.port=9649
56.2.4 Graphite
By default, metrics are exported to Graphite running on your local machine.
management.metrics.export.graphite.host=graphite.example.com
management.metrics.export.graphite.port=9004
56.2.5 Influx
By default, Influx are exported to Graphite running on your local machine.
management.metrics.export.influx.uri=http://influx.example.com:8086
56.2.6 JMX
Micrometer 对 JMX 提供了分层级的映射。
management.metrics.export.jmx.domain=com.example.app.metrics
HierarchicalNameMapper 类
56.2.7 New Relic
New Relic registry pushes metrics to New Relic periodically.
management.metrics.export.newrelic.api-key=YOUR_KEY
management.metrics.export.newrelic.account-id=YOUR_ACCOUNT_ID
management.metrics.export.newrelic.step=30s
56.2.8 Prometheus
56.2.9 SignalFx
SignalFx registry pushes metrics to SignalFx periodically.
management.metrics.export.signalfx.access-token=YOUR_ACCESS_TOKEN
management.metrics.export.signalfx.step=30s
56.2.10 Simple
56.2.11 StatsD
56.2.12 Wavefront
56.3 Supported Metrics
Spring Boot 会记录下面的指标:
- JVM metrics, report utilization of:
- Various memory and buffer pools
- Statistics related to garbage collection
- Threads utilization
- Number of classes loaded/unloaded
- CPU metrics
- File descriptor metrics
- Logback metrics: record the number of events logged to Logback at each level
- Uptime metrics: report a gauge for uptime and a fixed gauge representing the application’s absolute start time
- Tomcat metrics
- Spring Integration metrics
56.3.1 Spring MVC Metrics
management.metrics.web.server.auto-time-requests=true
如果为 false,可添加 @Timed 注解
@RestController
@Timed (1)
public class MyController {
@GetMapping("/api/people")
@Timed(extraTags = { "region", "us-east-1" }) (2)
@Timed(value = "all.people", longTask = true) (3)
public List<Person> listPeople() { ... }
}
(1). 该 controller 的所有方法都启用 timings
(2). 单独对某个方法启用 timings
(3). 对某个方法启用 longTask 的 timer
Spring MVC 默认可以记录的信息有:
- method:GET or POST
- uri: such as /api/person/{id}
- status: the response’s HTTP status code
- exception:
56.3.2 Spring WebFlux Metrics
和 Spring MVC Metrics 内容很相似
56.3.3 HTTP Client Metrics
Spring Boot Actuator 会记录 RestTemplate 和 WebClient 的行为。
记录的信息有:
- method:GET or POST
- uri: such as /api/person/{id}
- status: the response’s HTTP status code
- clientName: the host portion of the URI
56.3.4 Cache Metrics
56.3.5 DataSource Metrics
会记录连接池的当前数量,最大值和最小值。
56.3.6 Hibernate Metrics
56.3.7 RabbitMQ Metrics
56.4 Registering custom metrics
在你的组件注入 MeterRegistry
class Dictionary {
private final List<String> words = new CopyOnWriteArrayList<>();
Dictionary(MeterRegistry registry) {
registry.gaugeCollectionSize("dictionary.size", Tags.empty(), this.words);
}
// …
}
56.5 Customizing individual metrics
56.5.1 Common tags
56.5.2 Per-meter properties
56.6 Metrics endpoint
/actuator/metrics 列出了所有可用的指标名称。你可以选择某个指标深入查看,例如 /actuator/metrics/jvm.memory.max 。
还可以在 URL 后面添加任意数量的 tag=KEY:VALUE 查询参数,例如 /actuator/metrics/jvm.memory.max?tag=area:nonheap 。
57. Auditing
实现 AbstractAuthenticationAuditListener 和 AbstractAuthorizationAuditListener 接口来定制自己的安全事件。
你还可以在自己的业务事件使用审计服务,直接在你的组件注入 AuditEventRepository,或者通过 ApplicationEventPublisher 来发布一个 AuditApplicationEvent。
58. HTTP Tracing
Tracing 对于所有 HTTP 请求都是自动启用的,你可以查看 httptrace endpoint 获得关于最近 100 次请求和响应的信息。
58.1 Custom HTTP tracing
添加 trace 的内容的配置项:HttpExchangeTracer
或者注册你自己的 HttpExchangeTracer 实现。
InMemoryHttpTraceRepository 存储了最近 100 次的请求和响应信息,如要实现存储更多的请求信息,可通过实现自己的 HttpTraceRepository 来替换。
59. Process Monitoring
在 spring-boot 模块,你可以找到有两个类会创建一些监控进程监控的文件:
- ApplicationPidFileWriter: 在应用目录创建 application.pid,记录了应用的 PID。
- WebServerPortFileWriter: 在应用目录创建一个或多个 application.port 文件,记录了应用在使用的端口号。
这两个特性默认是没有启用的。
59.1 Extending Configuration
启用记录进程监控信息文件的特性,在 META-INF/spring.factories 添加配置:
org.springframework.context.ApplicationListener=org.springframework.boot.context.ApplicationPidFileWriter,org.springframework.boot.web.context.WebServerPortFileWriter
59.2 Programmatically
通过 SpringApplication.addListeners(…) 亦可实现。
60. Cloud Foundry Support
Spring Boot Actuator 还提供了关于云平台的支持,/cloudfoundryapplication 提供了一个可安全访问所有 @Endpoint bean 的路由。
访问 /cloudfoundryapplication 需要携带一个有效的 UAA token。
60.1 Disabling Extended Cloud Foundry Actuator Support
application.properties
management.cloudfoundry.enabled=false
60.2 Cloud Foundry Self-signed Certificates
/cloudfoundryapplication endpoints 的安全认证默认都是通过 SSL,如果你使用 self-signed 的证书,需要如下配置:
management.cloudfoundry.skip-ssl-validation=true
60.3 Custom context path
如果 server.servlet.context-path=/app,那么你的 Cloud Foundry endpoints 就是 /app/cloudfoundryapplication/*。
如果你希望 Cloud Foundry endpoints 不受服务器的 context-path 影响,需要显示添加一些配置。例如下面 Tomcat 的例子:
@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 (c, 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("/*");
};
}
61. What to Read Next
- sample applications
- Graphite
- deployment options