spring-boot-starter-actuator库主要用来暴露自身信息。有助于对应用程序进行监控和管理,以及采集一些应用指标。actuator通过 restful api 请求来监管、审计、收集应用的运行情况。
actuator每个restful api请求对应一个端点Endpoint。
Actuator模块不仅会根据应用依赖和配置自动创建出来的监控和管理端点Endpoint(原生端点: health、info、beans、httptrace、shutdown等等),同时我们也可以它的基础之上扩展实现一些自定义的监控需求(自定义端点)。
pom.xml文件添加spring-boot-actuator模块。
org.springframework.boot
spring-boot-starter-actuator
application.yml文件加入如下配置,当然大家可以根据自己的需求做修改。
# actuator监控
management:
# server:
# # 设置监控服务端口,如果没写默认就是服务器的端口
# port: 8081
endpoints:
# 设置端点是否可用 默认只有shutdown可用
enabled-by-default: true
web:
# 设置是否暴露端点 默认只有health和info可见
exposure:
# 包括所有端点
include: "*" # 注意需要添加引号
# 排除端点
exclude: shutdown
endpoint:
health:
show-details: always
#可以关闭指定的端点
shutdown:
enabled: false
属性配置主要是配置一些actuator endpoint的打开和关闭(配置是否可以用个HTTP的方式暴露出去,使得他们能被远程进入),关于属性的配置大家一看单词就能大概知道对应的意思。。
访问info Endpoint需要添加该插件
org.springframework.boot
spring-boot-maven-plugin
build-info
做完上面三个步骤Actuator我们就已经引入到我们项目中来了。
把应用程序跑起来,在应用程序启动过程中,我们可以找到如下打印。证明Actuator确实已经引入进来了。
Actuator里面已经默认给提供了大量的端点。如下:
Endpoints id | 描述 | HTTP方法 | 是否敏感信息 |
---|---|---|---|
auditevents | 显示当前应用程序的审计事件信息 | GET | Yes |
beans | 显示应用上下文中创建的所有Bean | GET | Yes |
caches | 显示可用缓存信息 | GET | Yes |
conditions | 显示自动装配类的状态及及应用信息 | GET | Yes |
configprops | 显示所有 @ConfigurationProperties 列表 | GET | Yes |
env | 显示 ConfigurableEnvironment 中的属性 | GET | Yes |
flyway | 显示 Flyway 数据库迁移信息 | GET | Yes |
health | 显示应用的健康信息(未认证只显示status,认证显示全部信息详情) | GET | No |
info | 显示任意的应用信息(在资源文件写info.xxx即可) | GET | No |
liquibase | 展示Liquibase 数据库迁移 | GET | Yes |
metrics | 提供应用运行状态的完整度量指标报告 | GET | Yes |
mappings | 显示所有 @RequestMapping 路径集列表 | GET | Yes |
scheduledtasks | 显示应用程序中的计划任务 | GET | Yes |
sessions | 允许从Spring会话支持的会话存储中检索和删除用户会话。 | GET | Yes |
shutdown | 允许应用以优雅的方式关闭(默认情况下不启用) | POST | Yes |
threaddump | 执行一个线程dump | GET | Yes |
httptrace | 显示HTTP跟踪信息(默认显示最后100个HTTP请求 - 响应交换) | GET | Yes |
大部分端点我们通过GET方式就能获取到对应的信息。部分端点需要POST请求,比如shutdown端点。关于actuator里面原生的端点,我们就主要就讲两个:health、metrics。
/health端点 用来获取应用的各类健康指标信息。在spring-boot-starter-actuator模块中自带实现了一些常用资源的健康指标检测器。这些检测器都通过HealthIndicator接口实现,并且会根据依赖关系的引入实现自动化装配,比如用于检测磁盘的DiskSpaceHealthIndicator、检测DataSource连接是否可用的DataSourceHealthIndicator等。actuator里面自带的健康指标检测器如下(当前前提是工程里面有使用到,比如如果程序里面有用到redis,health Endpoint里面就有带有Radis的健康检测):
健康指标检测器 | 解释 |
---|---|
CassandraHealthIndicator | 检查 Cassandra 数据库是否启动。 |
DiskSpaceHealthIndicator | 检查磁盘空间不足。 |
DataSourceHealthIndicator | 检查是否可以获得连接 DataSource。 |
ElasticsearchHealthIndicator | 检查 Elasticsearch 集群是否启动。 |
InfluxDbHealthIndicator | 检查 InfluxDB 服务器是否启动。 |
JmsHealthIndicator | 检查 JMS 代理是否启动。 |
MailHealthIndicator | 检查邮件服务器是否启动。 |
MongoHealthIndicator | 检查 Mongo 数据库是否启动。 |
Neo4jHealthIndicator | 检查 Neo4j 服务器是否启动。 |
RabbitHealthIndicator | 检查 Rabbit 服务器是否启动。 |
RedisHealthIndicator | 检查 Redis 服务器是否启动。 |
SolrHealthIndicator | 检查 Solr 服务器是否已启动。 |
我们要怎么才能看到health端点对应的信息呢。很简单,咱们不是说了其实每个端点就对应一个restful api请求。health Endpoint 对应GET请求。比如我们实例里面的health端点地址:http://127.0.0.1:2224/actuator/health 请求结果如下:(因为我们实例工程里面什么都没有,我连数据库都没有添加进去。所以你只能看到DiskSpaceHealthIndicator检测器检测到的diskSpace信息)
{
"status": "UP",
"details": {
"diskSpace": {
"status": "UP",
"details": {
"total": 264598032384,
"free": 210941227008,
"threshold": 10485760
}
},
"refreshScope": {
"status": "UP"
},
"discoveryComposite": {
"status": "UP",
"details": {
"discoveryClient": {
"status": "UP",
"details": {
"services": []
}
},
"eureka": {
"description": "Eureka discovery client has not yet successfully connected to a Eureka server",
"status": "UP",
"details": {
"applications": {}
}
}
}
},
"configServer": {
"status": "UNKNOWN",
"details": {
"error": "no property sources located"
}
},
"hystrix": {
"status": "UP"
}
}
}
虽然health 端点里面已经默认给实现了很多健康信息的检测。但是有的时候我们也想在health端点里面添加我们自定义的健康检测任务。有两种方式实现:继承AbstractHealthIndicator类、实现HealthIndicator接口。
我们可以通过自定义一个类继承自AbstractHealthIndicator类来实现我们自己的健康检测。比如有这样一个例子,我们自定义一个AllDiskSpaceAbstractHealthIndicator类检测所有磁盘的磁盘信息。代码如下
/**
* 通过自定义一个类继承AbstractHealthIndicator,往health端点添加数据
*
* allDiskSpace2 对应的信息会在 http://127.0.0.1:2224/actuator/health 里面显示出来
*/
@Component("allDiskSpace2")
public class AllDiskSpaceAbstractHealthIndicator extends AbstractHealthIndicator {
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
File[] rootFiles = File.listRoots();
if (rootFiles != null && rootFiles.length != 0) {
long total = 0, free = 0;
for (File file : rootFiles) {
total += file.getTotalSpace(); // 总量
free += file.getUsableSpace(); // 未用
}
long user = total - free; // 已用
double userRate = total == 0 ? 0 : ((double) user / total);// 利用率
builder.up()
.withDetail("diskspaceTotal", total)
.withDetail("diskspaceFree", free)
.withDetail("diskspaceUsage", userRate * 100)
.build();
} else {
builder.down().build();
}
}
}
然后我们再通过 http://127.0.0.1:2224/actuator/health 来访问下health端点,看下我们自定义的所有磁盘容量检测是否也更随一起返回了。注意在health端点返回的数据里面查找allDiskSpace2节点对应的数据。allDiskSpace2就是 @Component(“allDiskSpace2”)里面对应的allDiskSpace2。结果如下。
除了继承AbstractHealthIndicator类,我们也可以通过实现HealthIndicator接口的方式来实现自己的健康检测。代码如下:
/**
* 通过自定义一个类实现HealthIndicator接口,往health端点添加数据
* allDiskSpace0 对应的信息会在 http://127.0.0.1:2224/actuator/health 里面显示出来
*/
@Component("allDiskSpace0")
public class AllDiskSpaceHealthIndicator implements HealthIndicator {
@Override
public Health health() {
File[] rootFiles = File.listRoots();
if (rootFiles != null && rootFiles.length != 0) {
long total = 0, free = 0;
for (File file : rootFiles) {
total += file.getTotalSpace(); // 总量
free += file.getUsableSpace(); // 未用
}
long user = total - free; // 已用
double userRate = total == 0 ? 0 : ((double) user / total);// 利用率
return Health.up()
.withDetail("diskspaceTotal", total)
.withDetail("diskspaceFree", free)
.withDetail("diskspaceUsage", userRate * 100)
.build();
} else {
return Health.down().build();
}
}
}
程序跑起来,http://127.0.0.1:2224/actuator/health 返回的端点数据里是否有 allDiskSpace0 节点数据。
metrics端点用来返回当前应用的各类重要度量指标,比如:内存信息、线程信息、垃圾回收信息等。我们可以通过http://127.0.0.1:2224/actuator/metrics 请求来查看我们工程metrics端点所支持的度量指标(metrics更小的细粒度)有哪些。请求结果如下所示:
{
"names": [
"jvm.memory.max",
"process.files.max",
"jvm.gc.memory.promoted",
"tomcat.cache.hit",
"system.load.average.1m",
"tomcat.cache.access",
"jvm.memory.used",
"jvm.gc.max.data.size",
"jvm.memory.committed",
"system.cpu.count",
"logback.events",
"tomcat.global.sent",
"jvm.buffer.memory.used",
"tomcat.sessions.created",
"jvm.threads.daemon",
"system.cpu.usage",
"jvm.gc.memory.allocated",
"tomcat.global.request.max",
"tomcat.global.request",
"tomcat.sessions.expired",
"jvm.threads.live",
"jvm.threads.peak",
"tomcat.global.received",
"process.uptime",
"tomcat.sessions.rejected",
"process.cpu.usage",
"tomcat.threads.config.max",
"jvm.classes.loaded",
"jvm.gc.pause",
"jvm.classes.unloaded",
"tomcat.global.error",
"tomcat.sessions.active.current",
"tomcat.sessions.alive.max",
"jvm.gc.live.data.size",
"tomcat.servlet.request.max",
"tomcat.threads.current",
"tomcat.servlet.request",
"process.files.open",
"jvm.buffer.count",
"jvm.buffer.total.capacity",
"tomcat.sessions.active.max",
"tomcat.threads.busy",
"process.start.time",
"tomcat.servlet.error"
]
}
在知道了metrics端点支持的那些度量指标之后,我们就可以通过http://127.0.0.1:2224/actuator/metrics/{name} 的方式来请求获取每个度量指标对应的信息。比如我们可以通过 http://127.0.0.1:2224/actuator/metrics/jvm.memory.max 来获取 jvm.memory.max对应的信息。
虽然metrics端点里面已经给实现了很多度量指标的检测。metrics端点里面咱们也是可以加入自己的度量指标。我们还是以磁盘容量作为例子,我们准备在metrics里面添加 diskSpaceInfo.total、diskSpaceInfo.free、diskSpaceInfo.usage三个度量指标,并且计算出度量值。代码如下。
@Component
public class DiskMetrics implements MeterBinder {
private File rootFilePath;
public DiskMetrics() {
this.rootFilePath = new File(".");
}
@Override
public void bindTo(@NotNull MeterRegistry registry) {
// 磁盘已用容量
Gauge.builder("diskSpaceInfo.total", rootFilePath, File::getTotalSpace)
.register(registry);
// 磁盘剩余容量
Gauge.builder("diskSpaceInfo.free", rootFilePath, File::getFreeSpace)
.register(registry);
// 磁盘使用率
Gauge.builder("diskSpaceInfo.usage", rootFilePath, c -> {
long totalDiskSpace = rootFilePath.getTotalSpace();
if (totalDiskSpace == 0) {
return 0.0;
}
long usedDiskSpace = totalDiskSpace - rootFilePath.getFreeSpace();
return (double) usedDiskSpace / totalDiskSpace * 100;
})
.register(registry);
}
}
除了默认的这些health、metrics等端点之外。咱们也是可以自定义端点的。比如我们现在要自定义一个diskspace端点。展示磁盘信息。代码如下:注意添加@Configuration、@Endpoint(id = “diskspace”) 注解。
/**
* 自定义一个端点 id = diskspace 获取磁盘容量信息
*/
@Configuration
@Endpoint(id = "diskspace") // @EndPoint中的id不能使用驼峰法,需要以-分割
public class DiskSpaceEndPoint {
/**
* 获取自定义端点需要监测的数据 -- 磁盘容量信息
*
* @return Map
*/
@ReadOperation
public Map diskSpaceInfo() {
Map result = new HashMap<>();
// 获取磁盘容量信息
File[] rootFiles = File.listRoots();
if (rootFiles != null && rootFiles.length != 0) {
long total = 0;
long free = 0;
for (File file : rootFiles) {
total += file.getTotalSpace(); // 总量
free += file.getUsableSpace(); // 未用
}
long user = total - free; // 已用
double userRate = total == 0 ? 0 : ((double) user / total);// 利用率
result.put("diskspaceTotal", String.valueOf(total));
result.put("diskspaceFree", String.valueOf(free));
result.put("diskspaceUsage", String.valueOf(userRate * 100));
}
return result;
}
}
之后http://127.0.0.1:2224/actuator/diskspace 访问diskspace端点。结果如下:
{
"diskspaceTotal": "264598032384",
"diskspaceUsage": "20.483477416545355",
"diskspaceFree": "210399154176"
}
关于Actuator更加高级的用法大家可以去看下Prometheus,Prometheus是一个开源的系统监控及告警工具。
上文涉及到的实例代码下载地址
https://github.com/tuacy/microservice-framework。对应代码里面的actuator module