- 是什么:actuator( [ˈæktjʊeɪtə],制动器),是 Spring Boot 生产特性的套件之一
- 做什么:帮助你管理生产环境的应用,可以使用 HTTP,JMX 等管理应用
效果
[root@39b1ab8e279c /]# curl -s -X GET 'http://172.31.96.34:8080/actuator' | jq
{
"_links": {
"self": {
"href": "http://172.31.96.34:8080/actuator",
"templated": false
},
"customer": {
"href": "http://172.31.96.34:8080/actuator/customer",
"templated": false
},
"beans": {
"href": "http://172.31.96.34:8080/actuator/beans",
"templated": false
},
"caches-cache": {
"href": "http://172.31.96.34:8080/actuator/caches/{cache}",
"templated": true
},
"caches": {
"href": "http://172.31.96.34:8080/actuator/caches",
"templated": false
},
"health": {
"href": "http://172.31.96.34:8080/actuator/health",
"templated": false
},
"health-path": {
"href": "http://172.31.96.34:8080/actuator/health/{*path}",
"templated": true
},
"info": {
"href": "http://172.31.96.34:8080/actuator/info",
"templated": false
},
"conditions": {
"href": "http://172.31.96.34:8080/actuator/conditions",
"templated": false
},
"configprops": {
"href": "http://172.31.96.34:8080/actuator/configprops",
"templated": false
},
"env": {
"href": "http://172.31.96.34:8080/actuator/env",
"templated": false
},
"env-toMatch": {
"href": "http://172.31.96.34:8080/actuator/env/{toMatch}",
"templated": true
},
"loggers": {
"href": "http://172.31.96.34:8080/actuator/loggers",
"templated": false
},
"loggers-name": {
"href": "http://172.31.96.34:8080/actuator/loggers/{name}",
"templated": true
},
"heapdump": {
"href": "http://172.31.96.34:8080/actuator/heapdump",
"templated": false
},
"threaddump": {
"href": "http://172.31.96.34:8080/actuator/threaddump",
"templated": false
},
"prometheus": {
"href": "http://172.31.96.34:8080/actuator/prometheus",
"templated": false
},
"metrics-requiredMetricName": {
"href": "http://172.31.96.34:8080/actuator/metrics/{requiredMetricName}",
"templated": true
},
"metrics": {
"href": "http://172.31.96.34:8080/actuator/metrics",
"templated": false
},
"scheduledtasks": {
"href": "http://172.31.96.34:8080/actuator/scheduledtasks",
"templated": false
},
"mappings": {
"href": "http://172.31.96.34:8080/actuator/mappings",
"templated": false
}
}
}
Hello Actuator
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
- 配置 Endpoints
Endpoints(端点)是 Actuator 暴露出来用于监控应用和与应用交互的,比如 /health
可以用于查看应用的健康信息
默认的 Endpoints 配置如下(*
代表全部):
Property | Default |
---|---|
management.endpoints.jmx.exposure.exclude | |
management.endpoints.jmx.exposure.include | * |
management.endpoints.web.exposure.exclude | |
management.endpoints.web.exposure.include | health |
修改配置暴露全部 Endpoints
application.yml
# Actuator
management:
endpoints:
web:
exposure:
include: '*'
- 编写启动类,启动项目
SpringBootActuatorApp.java
@SpringBootApplication
public class SpringBootActuatorApp {
public static void main(String[] args) {
SpringApplication.run(SpringBootActuatorApp.class, args);
}
}
启动应用,可以看到已经暴露 Endpoint
...
2022-10-31 16:53:38.311 INFO 21580 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 15 endpoint(s) beneath base path '/actuator'
2022-10-31 16:53:38.345 INFO 21580 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
...
访问 http://localhost:8080/actuator/health 即可查看应用健康信息
[root@39b1ab8e279c /]# curl -X GET 'http://172.31.96.34:8080/actuator/health' -s | jq
{
"status": "UP"
}
常用 Endpoint
这里 是所有可用的 Endpoint
health
应用的健康信息,默认可查看的信息是比较少的,可以通过配置开启查看健康信息详情
application.yml
# Actuator
management:
endpoints:
web:
exposure:
include: '*'
# ------------ 展示详细健康信息-------------------
endpoint:
health:
show-details: always
# -------------------------------
show-details 的可选值如下:
Name | Description |
---|---|
never | 从不展示 |
always | 向所有用户展示 |
when-authorized | 只对授权用户展示,授权用户可以通过 management.endpoint.health.roles. 设置 |
重启之后再次查看,多了硬盘的使用情况和 ping 信息
[root@39b1ab8e279c /]# curl -X GET 'http://172.31.96.34:8080/actuator/health' -s | jq
{
"status": "UP",
"components": {
"diskSpace": {
"status": "UP",
"details": {
"total": 258390093824,
"free": 199666888704,
"threshold": 10485760,
"exists": true
}
},
"ping": {
"status": "UP"
}
}
}
此外,我们还可以自定义健康信息
@Component
public class CustomerHealthIndicator extends AbstractHealthIndicator {
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
builder
// 增加 details,需要在设置 management.endpoint.health.show-details
.withDetail("availableProcessors", Runtime.getRuntime().availableProcessors())
// 更改引用状态
.status(Status.UNKNOWN);
}
}
重启查看
[root@39b1ab8e279c /]# curl -X GET 'http://172.31.96.34:8080/actuator/health' -s | jq
{
"status": "UP",
"components": {
"customer": {
"status": "UNKNOWN",
"details": {
"availableProcessors": 8
}
},
"diskSpace": {
//....
}
}
metrics
Actuator 为 Micrometer 提供了依赖管理和自动配置, metrics 支持了对应用的持续监测, 结合监控系统(如 Prometheus)可对系统进行监测
Micrometer 为最流行的监控系统提供了一个简单的仪表客户端外观,允许您在没有供应商锁定的情况下对基于 JVM 的应用程序进行仪表化监控,
metrics 说明了可监测的指标,主要包括:
- JVM(垃圾收集器/内存/堆)
- 系统(运行时间、平均负载、处理器的信息)
- 线程池信息
- Tomcat 会话信息
- Spring MVC
- DataSource
- Prometheus / Grafana(图表展示,需要添加对应依赖)
[root@39b1ab8e279c /]# curl -X GET 'http://172.31.96.34:8080/actuator/metric' -s | jq
{
"timestamp": "2022-11-01T04:35:34.709+00:00",
"status": 404,
"error": "Not Found",
"message": "",
"path": "/actuator/metric"
}
[root@39b1ab8e279c /]# curl -X GET 'http://172.31.96.34:8080/actuator/metrics' -s | jq
{
"names": [
"http.server.requests",
"jvm.buffer.count",
"jvm.buffer.memory.used",
"jvm.buffer.total.capacity",
"jvm.classes.loaded",
"jvm.classes.unloaded",
"jvm.gc.live.data.size",
"jvm.gc.max.data.size",
"jvm.gc.memory.allocated",
"jvm.gc.memory.promoted",
"jvm.memory.committed",
"jvm.memory.max",
"jvm.memory.used",
"jvm.threads.daemon",
"jvm.threads.live",
"jvm.threads.peak",
"jvm.threads.states",
"logback.events",
"process.cpu.usage",
"process.start.time",
"process.uptime",
"system.cpu.count",
"system.cpu.usage",
"tomcat.sessions.active.current",
"tomcat.sessions.active.max",
"tomcat.sessions.alive.max",
"tomcat.sessions.created",
"tomcat.sessions.expired",
"tomcat.sessions.rejected"
]
}
对 Spring MVC 的监控包括了请求次数,响应时间,最大响应时间等,添加一个 Controller
TestController.java
@RestController
public class TestController {
@GetMapping("/test")
public String test(@RequestParam long time) throws InterruptedException {
TimeUnit.SECONDS.sleep(time);
return "SUCCESS";
}
}
重启并发送三次请求
[root@39b1ab8e279c /]# curl -X GET 'http://172.31.96.34:8080/test?time=1'
SUCCESS
[root@39b1ab8e279c /]# curl -X GET 'http://172.31.96.34:8080/test?time=2'
SUCCESS
[root@39b1ab8e279c /]# curl -X GET 'http://172.31.96.34:8080/test?time=3'
SUCCESS
通过 /actuator/prometheus
查看统计结果,该地址暴露的的信息用于 Prometheus 采集,做系统监控
[root@39b1ab8e279c /]# curl -X GET 'http://172.31.96.34:8080/actuator/prometheus'
...
# HELP http_server_requests_seconds
# TYPE http_server_requests_seconds summary
...
http_server_requests_seconds_count{exception="None",method="GET",outcome="SUCCESS",status="200",uri="/test",} 3.0
http_server_requests_seconds_sum{exception="None",method="GET",outcome="SUCCESS",status="200",uri="/test",} 6.0371463
...
# HELP http_server_requests_seconds_max
# TYPE http_server_requests_seconds_max gauge
...
http_server_requests_seconds_max{exception="None",method="GET",outcome="SUCCESS",status="200",uri="/test",} 3.0081005
...
其中的指标含义:
- http_server_requests_seconds_count:应用启动后该 uri 被请求的次数累加
- http_server_requests_seconds_sum:应用启动后该 uri 响应耗时累加
- http_server_requests_seconds_max:应用启动后该 uri 响应最大耗时
默认情况下,所有的 uri 都会被统计,可以通过设置 management.metrics.web.server.request.autotime.enabled
为 false
关闭全局拦截,然后使用 @Timed
注解对单个 uri 进行统计
TestController.java
@RestController
@Timed
public class TestController {
@GetMapping("/test")
@Timed(value = "test", longTask = true, extraTags = {"my-tag", "my-tag-value"})
public String test(@RequestParam long time) throws InterruptedException {
//...
}
}
@Timed
放在类上就会统计类中所有的方法,单独放在方法上只针对该方法统计
loggers
通过 /loggers 可以在运行时查看和修改应用所有日志配置
[root@39b1ab8e279c /]# curl -X GET 'http://172.31.96.34:8080/actuator/loggers' -s | jq
{
"levels": [
"OFF",
"ERROR",
"WARN",
"INFO",
"DEBUG",
"TRACE"
],
"loggers": {
"ROOT": {
"configuredLevel": "INFO",
"effectiveLevel": "INFO"
},
...
"org.noahnyy.demo.spring.boot": {
"configuredLevel": null,
"effectiveLevel": "INFO"
},
"org.noahnyy.demo.spring.boot.actuator": {
"configuredLevel": null,
"effectiveLevel": "INFO"
},
"org.noahnyy.demo.spring.boot.actuator.CustomerHealthIndicator": {
"configuredLevel": null,
"effectiveLevel": "INFO"
},
"org.noahnyy.demo.spring.boot.actuator.SpringBootActuatorApp": {
"configuredLevel": null,
"effectiveLevel": "INFO"
},
...
},
"groups": {
"web": {
"configuredLevel": null,
"members": [
"org.springframework.core.codec",
"org.springframework.http",
"org.springframework.web",
"org.springframework.boot.actuate.endpoint.web",
"org.springframework.boot.web.servlet.ServletContextInitializerBeans"
]
},
"sql": {
"configuredLevel": null,
"members": [
"org.springframework.jdbc.core",
"org.hibernate.SQL",
"org.jooq.tools.LoggerListener"
]
}
}
}
发送 POST 请求临时动态修改日志级别
[root@39b1ab8e279c /]# curl -s -X POST 'http://172.31.96.34:8080/actuator/loggers/ROOT' \
> -H 'Content-Type: application/json' \
> -d '{
> "configuredLevel": "DEBUG"
> }'
shutdown
关闭应用,高危操作,默认关闭
info
默认情况下 info 暴露从 InfoContributor
beans 收集到的信息,自动装配的 InfoContributors
包括了
Name | Description |
---|---|
EnvironmentInfoContributor | Exposes any key from the Environment under the info key. |
GitInfoContributor | Exposes git information if a git.properties file is available. 该文件可以通过 maven plugins 自动生成,详情戳 Generate git information |
BuildInfoContributor | Exposes build information if a META-INF/build-info.properties file is available. 该文件可以通过 maven plugins 自动生成,详情戳 Generate build information |
也可以通过配置文件自定义 info 信息
application.yml
info:
app:
name: '@project.name@'
'@project.name@'
的值在 mven 中设置,在 properties 文件中不需要添加单引号,如果 maven 没有使用 spring-booter-starter-parent,则需要添加
pom.xml
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<configuration>
<delimiters>
<delimiter>@</delimiter>
</delimiters>
<useDefaultDelimiters>false</useDefaultDelimiters>
</configuration>
</plugin>
</plugins>
</build>
重启项目
[root@39b1ab8e279c /]# curl -s -X GET 'http://172.31.96.34:8080/actuator/info' | jq
{
"app": {
"name": "demo-spring-boot-actuator"
}
}
自定义 Endpoint
可以通过自定义 Endpoint 暴露自己所需要的监控信息
@Component
@Endpoint(id = "customer")
public class CustomerEndpoint {
@ReadOperation
public String read() {
return "当前时间:" + new Date().toString();
}
@WriteOperation
public String write(String name, int id) {
return String.format("name: %s, id: %s", name, id);
}
@DeleteOperation
public String del(int id) {
return "id: " + id;
}
}
其中包括了读操作 @ReadOperation
,写操作 @WriteOperation
,删操作 @DeleteOperation
,对应的请求方式分别是 GET / POST / DELETE
[root@39b1ab8e279c /]# curl -s -X GET 'http://172.31.96.34:8080/actuator/customer' \
> -H 'Content-Type: application/json'
当前时间:Tue Nov 08 15:15:30 CST 2022
[root@39b1ab8e279c /]# curl -s -X POST 'http://172.31.96.34:8080/actuator/customer' \
> -H 'Content-Type: application/json' \
> -d '{"name": "noah", "id":1}'
name: noah, id: 1
[root@39b1ab8e279c /]# curl -s -X DELETE 'http://172.31.96.34:8080/actuator/customer?id=1'
id: 1
监控形式
Spring Boot Actuator 提供了两种形式的监控,分别是 HTTP 和 JMX
HTTP
访问 http://localhost:8080/actuator/[endpoint] 即可
JMX
JMX(Java Management Extensions)是 Java 自带的管理工具,通过 JMX,我们可以监控
- 服务器中的各种资源的使用情况,CPU、内存
- JVM 内存的使用情况
- JVM 线程使用情况
命令行输入 jconsole
进入可视化工具
选择刚启动的应用连接
可以看到应用资源情况,MBean 中便包含了 Spring 暴露出来的应用信息
自定义 MBean
我们可以自己实现 Java 提供的接口,创建 MBean
public interface SystemInfoMBean {
int getCpuCore();
long getTotalMemory();
void shutdown();
}
public class SystemInfo implements SystemInfoMBean {
@Override
public int getCpuCore() {
return Runtime.getRuntime().availableProcessors();
}
@Override
public long getTotalMemory() {
return Runtime.getRuntime().totalMemory();
}
@Override
public void shutdown() {
System.exit(0);
}
}
注册 MBean
public class CustomerJMBean {
public static void main(String[] args) throws MalformedObjectNameException, NotCompliantMBeanException, InstanceAlreadyExistsException, MBeanRegistrationException, IOException {
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
ObjectName objectName = new ObjectName("org.noahnyy.demo.spring.boot.actuator:type=SystemInfo");
SystemInfo systemInfo = new SystemInfo();
mBeanServer.registerMBean(systemInfo, objectName);
// 防止进程结束
System.in.read();
}
}
启动
也可以将 MBean 放在 Spring 生态中
@Component
public class MXBeanRegistrar implements ApplicationContextAware, EnvironmentAware, InitializingBean, DisposableBean {
private ConfigurableApplicationContext applicationContext;
private Environment environment = new StandardEnvironment();
private final ObjectName objectName = new ObjectName("org.noahnyy.demo.spring.boot.actuator:type=SystemInfo");
public MXBeanRegistrar() throws MalformedObjectNameException {
}
@Override
public void destroy() throws Exception {
ManagementFactory.getPlatformMBeanServer().unregisterMBean(this.objectName);
}
@Override
public void afterPropertiesSet() throws Exception {
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
server.registerMBean(new SystemInfo(), this.objectName);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = (ConfigurableApplicationContext) applicationContext;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
}