Actuator简介
什么是Spring Boot Actuator?
- Spring Boot Actuator 模块提供了生产级别的功能,比如健康检查,审计,指标收集,HTTP跟踪等,帮助我们监控和管理Spring Boot应用。
- 这个模块是一个采集应用内部信息暴露给外部的模块,上述的功能都可以通过HTTP和JMX访问。
- 因为暴露内部信息的特性,Actuator也可以和一些外部的应用监控系统整合(Prometheus, Graphite, DataDog等)。这些监控系统提供了出色的仪表板,图形,分析和警报,可帮助你通过一个统一友好的界面,监视和管理你的应用程序。
- Actuator使用Micrometer与这些外部应用程序监视系统集成。这样一来,只需很少的配置即可轻松集成外部的监控系统。
Micrometer为Java 平台上的性能数据收集提供了一个通用的API,应用程序只需要使用Micrometer的通用API来收集性能指标即可。Micrometer会负责完成与不同监控系统的适配工作,这就使得切换监控系统变得很容易。对比Slf4j之于Java Logger中的定位。
Endpoints介绍
Endpoints简介
Spring Boot提供了所谓endpoints(下文翻译为端点)用于外部系统与应用程序进行访问和交互。
例如,/health
端点提供了关于应用健康情况的一些基础信息。/metrics
端点提供了一些有用的应用程序指标(JVM 内存使用、系统CPU使用等)。
Endpoints类型
Actuator模块本来就有的端点我们称之为原生端点。根据端点的作用的话,我们大概可以分为三大类:
- 应用配置类: 获取应用程序中加载的应用配置、环境变量、自动化配置报告等与Spring Boot应用密切相关的配置类信息。
- 度量指标类: 获取应用程序运行过程中用于监控的度量指标,比如:内存信息、线程池信息、HTTP请求统计等。
- 操作控制类: 提供了对应用的关闭等操作类功能。
需要注意的就是:
- 每一个端点都可以通过配置来单独禁用或者启动
- 不同于Actuator 1.x,Actuator 2.x 的大多数端点默认被禁掉。 Actuator 2.x中的默认端点增加了
/actuator
前缀。默认暴露的两个端点为/actuator/health
和/actuator/info
Endpoints清单
此处使用的是SpringBoot 2.2.8版本,详情请查看Spring官方文件
Endpoint | HTTP方法 | 描述 |
---|---|---|
/actuator | GET | 查看有哪些Actuator endpoint是开放的 |
/actuator/auditevent | GET | 显示应用暴露的审计事件 (比如认证进入、订单失败),需要搭配Spring Security使用,示例代码 |
/actuator/beans | GET | 查看当前上下文中配置的所有的Bean |
/actuator/conditions | GET | 该端点用来获取应用的自动化配置报告,其中包括所有自动化配置的候选项。同时还列出了每个候选项自动化配置的各个先决条件是否满足。所以,该端点可以帮助我们方便的找到一些自动化配置为什么没有生效的具体原因。 |
/actuator/configprops | GET | 查看注入带有@ConfigurationProperties类的properties配置的属性和值,prefix代表前缀 |
/actuator/env (常用) | GET | 该端点与/configprops不同,它用来获取应用所有可用的环境属性报告。包括:环境变量、JVM属性、应用的配置配置、命令行中的参数(但是会自动过滤掉带有key、password、secret等关键字的properties的值,保护信息安全) |
/actuator/flyway | GET | 显示已应用的所有Flyway数据库迁移 |
/actuator/health (常用) | GET | 查看当前SpringBoot运行的健康指标,值由HealthIndicator的实现类提供(所以可以自定义一些健康指标信息) |
/actuator/heapdump | GET | 会自动生成一个JVM的堆文件 |
/actuator/info | GET | 展示了关于应用的一般信息,这些信息从编译文件比如META-INF/build-info.properties或者Git文件比如git.properties或者任何环境的property中获取。 |
/actuator/mappings | GET | 查看全部的endpoint(包含 Actuator 的),即路径列表 |
/actuator/metrics(常用) | GET | 查看有哪些指标可以看(ex: jvm.memory.max、system.cpu.usage),使用/actuator/metrics/{metric.name}可以查看各指标的详细信息 |
/actuator/scheduledtasks | GET | 查看定時任务的信息 |
/actuator/shutdown | POST | 唯一一个需要POST请求的endpoint,使应用程序正常关闭 |
更多详细的EndPoint可以查看:Spring Boot Actuator [监控与管理]
集成 Actuator
创建示例项目
我们先创建一个demo应用,可以通过Spring Initializr创建:
引入依赖
Maven
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Gradle
dependencies {
compile("org.springframework.boot:spring-boot-starter-actuator")
}
端点配置
默认暴露端点
我们可以通过以下配置,来配置通过JMX 和 HTTP 暴露的端点。
Property | Default |
---|---|
management.endpoints.jmx.exposure.exclude | |
management.endpoints.jmx.exposure.include | * |
management.endpoints.web.exposure.exclude | |
management.endpoints.web.exposure.include | info, healt |
考虑到安全因素,Actuator默认只开放了/actuator/health
和/actuator/info
这两个endpoint,如果要开放其他endpoint,需要额外在application.properties中进行设置。
暴露配置
① 打开所有的监控点
management:
endpoints:
enabled-by-default: true #暴露所有端点信息
web:
exposure:
include: '*' #以web方式暴露(不包含shutdown)
② 开放指定的endpoint
management:
endpoints:
enabled-by-default: true #暴露所有端点信息
web:
exposure:
include: beans,mappings # 如果指定多个端点,用","分开
③ 关闭指定的endpoint
management:
endpoints:
web:
exposure:
exclude: beans# 如果指定多个端点,用","分开
include: *
exclude通常会跟include一起用,就是先include了全部,然后再exclude/actuator/beans
这个endpoint。
④ 开放shutdown,需额外配置
management:
endpoints:
shutdown:
enabled: true
路径配置
① 默认情况下所有端点都暴露在/actuator
路径下,也可以改变/actuator
的路径,可以自定义:
management:
endpoints:
web:
base-path: /monitor
设置完重启后,原本內建的/actuator/xxx
路径,都会变成/monitor/xxx
,可以用来防止被其他人猜到。
② 支持单个endpoint路径定义,比如将health修改成healthcheck
management:
endpoints:
web:
path-mapping:
health: healthcheck
管理端口调整
management:
server:
port: 11011
自定义端口,默认跟server.port
一样,可以防止被其他人猜到
端点响应缓存
对于一些不带参数的端点请求会自动进行缓存,我们可以通过如下方式配置缓存时间,下面配置表示 beans端点的缓存时间为100s
management:
endpoint:
beans:
cache:
time-to-live: 100s
端点保护
如果开启了Actuator默认不开放的endpoints,建议一定要加上Spring Security
用于endpoint保护,避免重要信息泄露,必须防止未经授权的外部访问。
这里我们使用Spring Security
保护,首先添加相关依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
添加之后,我们需要定义安全校验规则,来覆盖Spring Security
的默认配置。
这里给出两个版本的模板配置:
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.boot.actuate.context.ShutdownEndpoint;
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
public class ActuatorSecurityConfig extends WebSecurityConfigurerAdapter {
/*
* version1:
* 1. 限制 '/shutdown'端点的访问,只允许ACTUATOR访问
* 2. 允许外部访问其他的端点
* 3. 允许外部访问静态资源
* 4. 允许外部访问 '/'
* 5. 其他的访问需要被校验
* version2:
* 1. 限制所有端点的访问,只允许ACTUATOR访问
* 2. 允许外部访问静态资源
* 3. 允许外部访问 '/'
* 4. 其他的访问需要被校验
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
// version1
// http
// .authorizeRequests()
// .requestMatchers(EndpointRequest.to(ShutdownEndpoint.class))
// .hasRole("ADMIN")
// .requestMatchers(EndpointRequest.toAnyEndpoint())
// .permitAll()
// .requestMatchers(PathRequest.toStaticResources().atCommonLocations())
// .permitAll()
// .antMatchers("/")
// .permitAll()
// .antMatchers("/**")
// .authenticated()
// .and()
// .httpBasic();
// version2
http
.authorizeRequests()
.requestMatchers(EndpointRequest.toAnyEndpoint())
.hasRole("ADMIN")
.requestMatchers(PathRequest.toStaticResources().atCommonLocations())
.permitAll()
.antMatchers("/")
.permitAll()
.antMatchers("/**")
.authenticated()
.and()
.httpBasic();
}
}
application.properties
的相关配置如下:
# Spring Security Default user name and password
spring.security.user.name=actuator
spring.security.user.password=actuator
spring.security.user.roles=ADMIN
我们使用浏览器访问http://localhost:8080/actuator/health
端点接口,会先弹出个登录框,只有登录后才能访问。
定制Endpoint
定制化health信息
① 配置Health显示情况,详细界面显示配置
management:
health:
enabled: true
show-details: always #总是显示详细信息。可显示每个模块的状态信息
② 定制Health Endpoint
添加信息:
1)继承 AbstractHealthIndicator 类
2)定义参数 Health.Builder builder
3)向参数 builder 中添加状态及相关信息
@Component
//类名截去HealthIndicator后,为显示时的组件名
public class MyComHealthIndicator extends AbstractHealthIndicator {
//真实的检查方法
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
// 获取链接进行测试
Map<String, Object> map = new HashMap<>();
//检查完成
if (1 == 1) {
//健康
builder.status(Status.UP);
map.put("count", 1);
} else {
//不健康
builder.status(Status.OUT_OF_SERVICE);
map.put("err", "连接超时");
map.put("time", 3000);
}
builder.withDetail("code", 100)
.withDetails(map);
}
}
定制info信息
编写InfoContributor
1)继承 public class ExampleInfoContributor implements InfoContributor
2)定义 Info.Builder builder 参数
3)向builder中添加参数信息
@Component
public class ExampleInfoContributor implements InfoContributor {
@Override
public void contribute(Info.Builder builder) {
builder.withDetail("msg", "你好")
.withDetail("hello", "uclass")
.withDetails(Collections.singletonMap("key", "value"));
}
}
定制Metrics信息
① 利用service层构造器,在注册中心中添加cityService.saveCity.count指标
@Service
public class CityServiceImpl implements CityServices {
@Autowired
CityMapper cityMapper;
Counter counter;
//利用构造器,在注册中心中添加cityService.saveCity.count指标
public CityServiceImpl(MeterRegistry meterRegistry) {
//指标中心注册新的指标项
counter = meterRegistry.counter("cityService.saveCity.count");
}
public void saveCity(City city) {
counter.increment();
cityMapper.insertCity(city);
}
}
② 在配置类中新建配置,添加指标
@ServletComponentScan(basePackages = "com.uclass.thymeleaf")
@Configuration
public class AdminWebConfig implements WebMvcConfigurer {
@Bean
MeterBinder queueSize(Queue queue) {
return (registry) -> Gauge.builder("queueSize", queue::size).register(registry);
}
}
//利用构造器,在注册中心中添加cityService.saveCity.count指标
public CityServiceImpl(MeterRegistry meterRegistry) {
//指标中心注册新的指标项
counter = meterRegistry.counter("cityService.saveCity.count");
}
自定义新端点
利用 @Endpoint(id = “myservice”) 注解
- id属性代表新增的端点名称
- 利用@ReadOperation、@WritOperation注解,在端点中添加信息
@Component
@Endpoint(id = "myservice")
public class MyServiceEndPoint {
@ReadOperation
public Map getDockerInfo () {
//端点的读操作
return Collections.singletonMap("dockerInfo", "docker start...");
}
@WriteOperation
private void restartDocker(){
System.out.println("docker restarted....");
}
}
参考资料
SpringBoot 指标监控——Actuator
Spring boot——Actuator 详解