暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

服务端性能监控最佳实践(二)—— Spring Boot Actuator介绍

重口味码农 2020-03-27
1118

服务端性能监控最佳实践(二)—— Spring Boot Actuator介绍

@[toc] 监控后台服务是否正常运行,有很多指标需要我们关注,一是机器本身的状态,比如CPU利用率、磁盘使用率、内存、网络等,通过这些来判断机器是否运行正常。这些是属于机器指标,一般云服务商会提供。今天我们要分析的是程序的性能指标,因为即使机器正常,但程序可能已经挂了。

对java程序来说,我们主要关注JVM的状态是否正常,希望能把一般通过 jconsole
得到的数据能通过监控自动获取出趋势图。此时我们就需要一个非常强大的模块: SpringBootActuator
来帮助获取到应用的统计信息。SpringBootActuator
不止能提供jvm相关信息,也能对应用相关依赖做健康检查,功能十分强大,接入非常简单。

给一个Maven项目增加Actuator

使用如下依赖

  1. <dependency>

  2. <groupId>org.springframework.boot</groupId>

  3. <artifactId>spring-boot-starter-actuator</artifactId>

  4. </dependency>

介绍Endpoints

Endpoints是Actuator中的端点,每个端点都提供了不同的功能,Actuator内置了很多Endpoints,配置就可以使用。

/health
提供了应用健康信息。

/info
提供了应用基本信息。

/logfile
可以直接查看日志文件等等。

同时我们也可以定义自己的Endpoints,以此来自定义想要的监控项。

查看所有endpoints

启动项目,访问http://localhost:8080/actuator查看,你应该能看到如下列表

  1. {

  2. "_links":{

  3. "self":{

  4. "href":"http://localhost:7777/actuator",

  5. "templated":false

  6. },

  7. "auditevents":{

  8. "href":"http://localhost:7777/actuator/auditevents",

  9. "templated":false

  10. },

  11. "health":{

  12. "href":"http://localhost:7777/actuator/health",

  13. "templated":false

  14. },

  15. "env":{

  16. "href":"http://localhost:7777/actuator/env",

  17. "templated":false

  18. }

  19. }

  20. }

访问/actuator获取到的是当前已开启的endpoints列表,有一些文档说很多endpoints是默认开启的,但从Spring Boot2.0之后,因为安全原因,大部分的endpoints都是默认关闭的了,需要在配置文件中手动开启。

配置endpoints的开关

在配置文件中,可以通过 include
exclude
配置endpoint在http或jmx中是否开启或关闭,如下。

  1. management:

  2. endpoints:

  3. web:

  4. exposure:

  5. exclude: shutdown

  6. include: ["auditevents", "info", "health", "metrics", "loggers", "logfile", "httptrace", "env", "flyway", "mappings",

  7. "scheduledtasks", "prometheus"]

  8. jmx:

  9. exposure:

  10. include: * #所有

这样就能在 /actuator
页面看到大多数的endpoints了。

重要的endpoint

iddesc
auditevents
显示当前应用程序的审计事件信息
beans
显示应用Spring Beans的完整列表
caches
显示可用缓存信息
conditions
显示自动装配类的状态及及应用信息
configprops
显示所有 @ConfigurationProperties 列表
env
显示 ConfigurableEnvironment 中的属性
flyway
显示 Flyway 数据库迁移信息
health
显示应用的健康信息(未认证只显示 status
,认证显示全部信息详情)
info
显示任意的应用信息(在资源文件写info.xxx即可)
liquibase
展示Liquibase 数据库迁移
metrics
展示当前应用的 metrics 信息
mappings
显示所有 @RequestMapping 路径集列表
scheduledtasks
显示应用程序中的计划任务
sessions
允许从Spring会话支持的会话存储中检索和删除用户会话。
shutdown
允许应用以优雅的方式关闭(默认情况下不启用)
threaddump
执行一个线程dump
httptrace
显示HTTP跟踪信息(默认显示最后100个HTTP请求 - 响应交换)

/actuator/httptrace

可以查看近期的请求详细数据,比如参数、cookie等

/actuator/scheduledtasks

显示定时任务列表

  1. {

  2. "cron": [

  3. {

  4. "runnable": {

  5. "target": "com.test.test.test.test.test.refresh"

  6. },

  7. "expression": " 0 0 0 1 1/1 ? "

  8. }

  9. ],

  10. "fixedDelay": [],

  11. "fixedRate": [],

  12. "custom": []

  13. }

/actuator/mappings

显示所有的@RequestMapping 路径

/actuator/metrics

显示metrics数据。

/actuator/health

health是比较重要的一个endpoint,因为它本身自带了许多健康检查,可以对我们的线上监控起到非常重要的作用。

/health默认只返回一个简单的 UP
DOWN
的status信息,想要看到全部数据,需要修改xml配置。

  1. management:

  2. endpoint:

  3. health:

  4. show-details: always #展示所有细节内容

这样我们访问就可以看到如下信息

  1. // 省略了一些detail信息

  2. {

  3. "status":"UP",

  4. "details":{

  5. "db":{

  6. "status":"UP",

  7. "details":{

  8. "dataSource":{

  9. "status":"UP"

  10. }

  11. }

  12. },

  13. "refreshScope":{

  14. "status":"UP"

  15. },

  16. "discoveryComposite":{

  17. "status":"UP",

  18. "details":{

  19. "discoveryClient":{

  20. "status":"UP",

  21. "details":{


  22. }

  23. },

  24. "eureka":{

  25. "description":"Remote status from Eureka server",

  26. "status":"UNKNOWN",

  27. "details":{


  28. }

  29. }

  30. }

  31. },

  32. "redis":{

  33. "status":"UP",

  34. "details":{

  35. "version":"2.8.13"

  36. }

  37. }

  38. }

  39. }

可以看到db 、redis、eureka等许多重要依赖的健康信息。如果其中有一个为DOWN,那么应用的整体状态就是DOWN。

我们之所以能看到这些信息的原理是它们都实现了 HealthIndicator
接口,会返回自身的健康状态,如果我们需要定义自定义的健康指标的话,也是需要实现这个接口或继承 AbstractHealthIndicator
,重写其中的 doHealthCheck
方法,后面会会讲解这种方式。

已经实现这个接口的有

名称描述
CassandraHealthIndicator
检查 Cassandra
 数据库是否启动。
DiskSpaceHealthIndicator
检查磁盘空间不足。
DataSourceHealthIndicator
检查是否可以获得连接 DataSource
ElasticsearchHealthIndicator
检查 Elasticsearch
 集群是否启动。
InfluxDbHealthIndicator
检查 InfluxDB
 服务器是否启动。
JmsHealthIndicator
检查 JMS
 代理是否启动。
MailHealthIndicator
检查邮件服务器是否启动。
MongoHealthIndicator
检查 Mongo
 数据库是否启动。
Neo4jHealthIndicator
检查 Neo4j
 服务器是否启动。
RabbitHealthIndicator
检查 Rabbit
 服务器是否启动。
RedisHealthIndicator
检查 Redis
 服务器是否启动。
SolrHealthIndicator
检查 Solr
 服务器是否已启动。

自定义健康指标

比如我的项目中,并没有用es默认的client,而是自己去创建一个es的 RestLowLevelClientt
,以此来跳过https证书检查。这样我就没有办法使用 ElasticsearchHealthIndicator
,因为它肯定会一直返回down,只能自己实现一个HealthIndicator接口或继承 AbstractHealthIndicator
类。如下代码(检查逻辑是参照的 ElasticsearchHealthIndicator

  1. public class EsRestLowLevelClientHealthIndicator extends AbstractHealthIndicator {

  2. private static final String RED_STATUS = "red";

  3. private final JsonParser jsonParser;


  4. private RestLowLevelClient restLowLevelClient;


  5. @Autowired

  6. public EsRestLowLevelClientHealthIndicator(RestLowLevelClient restLowLevelClient) {

  7. this.restLowLevelClient = restLowLevelClient;

  8. this.jsonParser = JsonParserFactory.getJsonParser();;

  9. }


  10. @Override

  11. protected void doHealthCheck(Health.Builder builder) throws Exception {

  12. Response response = this.restLowLevelClient.performRequest(new Request("GET", "/_cluster/health/"));

  13. StatusLine statusLine = response.getStatusLine();

  14. if (statusLine.getStatusCode() != 200) {

  15. builder.down();

  16. builder.withDetail("statusCode", statusLine.getStatusCode());

  17. builder.withDetail("reasonPhrase", statusLine.getReasonPhrase());

  18. } else {

  19. InputStream inputStream = response.getEntity().getContent();

  20. Throwable var5 = null;


  21. try {

  22. this.doHealthCheck(builder, StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8));

  23. } catch (Throwable var14) {

  24. var5 = var14;

  25. throw var14;

  26. } finally {

  27. if (inputStream != null) {

  28. if (var5 != null) {

  29. try {

  30. inputStream.close();

  31. } catch (Throwable var13) {

  32. var5.addSuppressed(var13);

  33. }

  34. } else {

  35. inputStream.close();

  36. }

  37. }


  38. }


  39. }

  40. }


  41. private void doHealthCheck(Health.Builder builder, String json) {

  42. Map<String, Object> response = this.jsonParser.parseMap(json);

  43. String status = (String)response.get("status");

  44. if (RED_STATUS.equals(status)) {

  45. builder.outOfService();

  46. } else {

  47. builder.up();

  48. }


  49. builder.withDetails(response);

  50. }

  51. }

这个类加载到Spring中,在访问 /actuator/health
时就会得到如下信息。

  1. {

  2. "status":"UP",

  3. "details":{

  4. "esRestLowLevelClient":{

  5. "status":"UP",

  6. "details":{

  7. "cluster_name":"shark",

  8. "status":"yellow",

  9. "timed_out":false,

  10. "number_of_nodes":26,

  11. "number_of_data_nodes":26,

  12. "active_primary_shards":10009,

  13. "active_shards":20105,

  14. "relocating_shards":0,

  15. "initializing_shards":0,

  16. "unassigned_shards":14,

  17. "delayed_unassigned_shards":0,

  18. "number_of_pending_tasks":0,

  19. "number_of_in_flight_fetch":0,

  20. "task_max_waiting_in_queue_millis":0,

  21. "active_shards_percent_as_number":99.93041403648293

  22. }

  23. }

  24. }

  25. }

可以看到我们自定义的 esRestLowLevelClient
指标为UP状态。

通过 /actuator/health
,我们可以写一个定时器对应用做黑盒监控,判断返回值是否为UP,否则报警,就可以很容易地对应用和依赖做出监控了。

结语

上面主要介绍了 SpringBootActuator
的作用和用法,可以看出它是一个开箱即用、功能强大的组件,除了上面介绍了的还有修改日志等级、管理session等功能,大家可以尝试加入到自己项目中,能大大地提高监控效率。下一篇我们会分享如何把jvm监控数据展示到Grafana中,得到详细的性能监控图表。如下图

本文首发于重口味博客https://blog.csdn.net/acingdreamer,欢迎大家关注


文章转载自重口味码农,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论