Spring Boot 应用监控:Actuator与 Admin

第 III 部分Spring Boot 系统监控、测试与运维

Spring Boot 应用监控:Actuator与 Admin

《Spring Boot 实战开发》(陈光剑)
—— 基于 Gradle + Kotlin的企业级应用开发最佳实践

在企业级应用中,对系统进行运行状态监控通常是必不可少的。Spring Boot提供了 Actuator 模块实现应用的监控与管理,对应的起步依赖是spring-boot-starter-actuator。
spring-boot-actuator模块提供了一个监控和管理生产环境的模块,可以使用http、jmx、ssh、telnet等拉管理和监控应用。它提供了应用的审计(Auditing)、健康(health)状态信息、数据采集(metrics gathering)统计等监控运维的功能。同时,我们可以扩展 Actuator 端点(Endpoint) 自定义监控指标。这些指标都是以 JSON 接口数据的方式呈现。而使用 Spring Boot Admin 可以实现这些 JSON 接口数据的界面展现。
本章介绍 Spring Boot Actuator 和使用Spring Boot Admin实现对 Spring Boot应用的监控与管理。
1.1 Actuator简介
在实际的生产系统中,我们怎样知道我们的应用运行良好呢?我们往往需要对系统实际运行的情况(例如cpu、io、disk、db、业务功能等指标)进行监控运维。这需要耗费我们不少精力来搞这些工作。
在SpringBoot中,我们完全不需要面对这样的难题。Spring Boot Actuator 提供了众多 HTTP 接口端点(Endpoint),其中包含了丰富的 Spring Boot 应用程序运行时的内部状态信息。同时,我们还可以自定义监控端点实现灵活定制。
Actuator是spring boot提供的对应用系统的自省和监控功能,Actuator对应用系统本身的自省功能,可以让我们方便快捷的实现线上运维监控的工作。这个有点DevOps的味道。通过Actuator,我们可以使用数据化的指标去度量我们的应用的运行情况。比如查看服务器的磁盘、内存、CPU 等信息,系统运行了多少线程,gc的情况,运行状态等等。

spring-boot-actuator模块提供了一个监控和管理生产环境的模块,可以使用http、jmx、ssh、telnet等拉管理和监控应用。
随着devops的兴起,以及docker技术的普及,微服务在一定场合会越来越受欢迎。即使不说微服务,springboot这种可以直接内嵌web服务器打成一个jar包的方式,也更符合devops的趋势:打成个jar包,往服务器上一扔,十分方便,自带Actuator,把监控也给省了一大半,真正做到了可以把精力花在刀刃上。
1.2 启用 Actuator
在 Spring Boot项目中添加Actuator 起步依赖即可启用 Actuator 功能。在 Gradle项目配置文件build.gradle中添加如下:

dependencies {
    compile('org.springframework.boot:spring-boot-starter-actuator')
    ...
}   

为了看到 Spring Boot 中提供的全部的端点信息,在 Spring Boot 1.5.x 版本中默认启用所有 Endpoint,这些端点如下:

{
  "links" : [ {
    "rel" : "self",
    "href" : "http://127.0.0.1:8010/actuator"
  }, {
    "rel" : "metrics",
    "href" : "http://127.0.0.1:8010/metrics"
  }, {
    "rel" : "autoconfig",
    "href" : "http://127.0.0.1:8010/autoconfig"
  }, {
    "rel" : "configprops",
    "href" : "http://127.0.0.1:8010/configprops"
  }, {
    "rel" : "dump",
    "href" : "http://127.0.0.1:8010/dump"
  }, {
    "rel" : "trace",
    "href" : "http://127.0.0.1:8010/trace"
  }, {
    "rel" : "logfile",
    "href" : "http://127.0.0.1:8010/logfile"
  }, {
    "rel" : "beans",
    "href" : "http://127.0.0.1:8010/beans"
  }, {
    "rel" : "env",
    "href" : "http://127.0.0.1:8010/env"
  }, {
    "rel" : "heapdump",
    "href" : "http://127.0.0.1:8010/heapdump"
  }, {
    "rel" : "serverEndpoint",
    "href" : "http://127.0.0.1:8010/serverEndpoint"
  }, {
    "rel" : "jolokia",
    "href" : "http://127.0.0.1:8010/jolokia"
  }, {
    "rel" : "info",
    "href" : "http://127.0.0.1:8010/info"
  }, {
    "rel" : "loggers",
    "href" : "http://127.0.0.1:8010/loggers"
  }, {
    "rel" : "showEndpoints",
    "href" : "http://127.0.0.1:8010/showEndpoints"
  }, {
    "rel" : "auditevents",
    "href" : "http://127.0.0.1:8010/auditevents"
  }, {
    "rel" : "health",
    "href" : "http://127.0.0.1:8010/health"
  }, {
    "rel" : "docs",
    "href" : "http://127.0.0.1:8010/docs"
  }, {
    "rel" : "mappings",
    "href" : "http://127.0.0.1:8010/mappings"
  } ]
}

在 Spring Boot 2.0中,Actuator 模块做了较大更新,默认启用的端点如下:

{
_links: {
self: {
href: "http://127.0.0.1:8008/actuator",
templated: false
},
health: {
href: "http://127.0.0.1:8008/actuator/health",
templated: false
},
info: {
href: "http://127.0.0.1:8008/actuator/info",
templated: false
}
}
}

如果想启用所有 Endpoint,在application.properties中配置如下:

#endpoints in Spring Boot 2.0
#http://127.0.0.1:8008/actuator
management.endpoints.enabled-by-default=true
management.endpoints.web.expose=*

重新启动应用,我们将看到一个信息更全的 Actuator 端点列表,这个列表我们将在下面小节中看到。

如果是默认启用所有 Actuator 端点,但是想要禁用某些端点信息,可以配置如下:

management.endpoint.beans.enabled=false
management.endpoint.info.enabled=false
management.endpoint.health.enabled=false

这样再访问 http://127.0.0.1:8008/actuator ,我们将不会看到/beans、 /info、/health的端点信息了。另外,我们可以通过 application.properties 中的属性定制 Actuator 的使用。完整的 Actuator 配置属性列表参考application.properties 中的:

# ----------------------------------------
# ACTUATOR PROPERTIES
# ----------------------------------------

部分。这些配置属性都在management.*命名空间下。

提示 :本节的实例工程代码在:https://github.com/KotlinSpringBoot/ksb_with_security/tree/front_back_end_2018.2.2 中。

更多关于 Spring Boot 2.0中的 Actuator 的介绍参考:https://docs.spring.io/spring-boot/docs/2.0.x/actuator-api/html/

1.4 自定义Actuator Endpoint

Spring Boot Actuator 模块提供了灵活的接口,方便我们自己定制监控端点。例如Endpoint、PublicMetrics、HealthIndicator、CounterService、GaugeService接口等。 为了跟下一小节中介绍 Spring Boot Admin (目前仅支持 Spring Boot >=1.5.9.RELEASE and <2.0.0.M1版本)衔接,本节基于Spring Boot 1.5.10中 Actuator模块。
1.4.1 Endpoint接口
SpringBoot的Endpoint主要是用来监控应用服务的运行状况,并在Mvc中集成以提供HTTP接口。内置的Endpoint比如HealthEndpoint会监控disk和db的状况:

图14-1 HealthEndpoint会监控disk和db的状况
MetricsEndpoint则会监控内存和gc等指标的状况:

{
  "mem": 1089990,
  "mem.free": 86536,
  "processors": 4,
  "instance.uptime": 796368,
  "uptime": 829333,
  "systemload.average": 5.74365234375,
  "heap.committed": 968704,
  "heap.init": 131072,
  "heap.used": 881143,
  "heap": 2097152,
  …
}

Endpoint的接口协议如下

    public interface Endpoint<T> {
        String getId();
        boolean isEnabled();
        boolean isSensitive();
        T invoke(); 
    }
    

1.4.2 实现Endpoint接口
下面我们来自定义一个显示当前 Spring Boot 应用程序运行机器的信息。这个端点ID 是 /serverEndpoint,输出的数据结构是Map<String, Map<String, String>>, 示例数据如下:

// 20180207113759
// http://127.0.0.1:8010/serverEndpoint

{
  "ServerInfo": {
    "hostAddress": "127.0.0.1",
    "hostName": "jacks-MacBook-Air.local",
    "OS": "Mac OS X"
  },
  "DiskInfo": {
    "freeSpace": "3143M",
    "usableSpace": "2893M",
    "totalSpace": "114544M"
  },
  "MemInfo": {
    "totalPhysicalMemorySize": "8192M",
    "freePhysicalMemorySize": "84M",
    "committedVirtualMemorySize": "6225M",
    "freeSwapSpaceSize": "1314M",
    "totalSwapSpaceSize": "7168M",
    "processCpuLoad": "0.1716696728153335",
    "systemCpuLoad": "0.8331151832460733",
    "processCpuTime": "1401557475000",
    "arch": "x86_64",
    "availableProcessors": "4",
    "systemLoadAverage": "5.63134765625",
    "version": "10.12.1"
  }
}

完整的实现代码在ServerEndpoint.kt 中。可参考示例工程源代码。
启动应用,通过http://127.0.0.1:8010/actuator 我们可以看到 /serverEndpoint 端点的信息

{
  "links": [
    {
      "rel": "self",
      "href": "http://127.0.0.1:8010/actuator"
    },
    {
      "rel": "metrics",
      "href": "http://127.0.0.1:8010/metrics"
    },
    …
    {
      "rel": "serverEndpoint",
      "href": "http://127.0.0.1:8010/serverEndpoint"
    },
    …
  ]
}

访问其中的: http://127.0.0.1:8010/serverEndpoint ,可以看到输出数据如下:

1.4.3 继承AbstractEndpoint抽象类

Spring Boot Actuator 内置的/env 端点实现代码在EnvironmentEndpoint中。其中的关键代码如下:

@ConfigurationProperties(prefix = "endpoints.env")
public class EnvironmentEndpoint extends AbstractEndpoint<Map<String, Object>> {
  …
  @Override
  public Map<String, Object> invoke() {
    Map<String, Object> result = new LinkedHashMap<String, Object>();
    …
  }
  ...
}  

可以看出,EnvironmentEndpoint是继承AbstractEndpoint抽象类,重写invoke() 方法来实现的。所以,我们也可以通过这种方法来自定义端点。
下面我们实现一个显示 Spring Boot应用中所有端点信息(类似 /actuator 功能)的 /showEndpoints。这个端点输出的数据结构如下

{
  "serverEndpoint": {
    "id": "serverEndpoint",
    "enabled": true,
    "sensitive": false
  },
  "showEndpoints": {
    "id": "showEndpoints",
    "enabled": true,
    "sensitive": false
  },
  ..
}

首先,声明一个ShowEndpoints 类,它继承AbstractEndpoint抽象类并实现ApplicationContextAware接口:

@Component
class ShowEndpoints :
        AbstractEndpoint<MutableMap<String, MyEndpoint>?>("showEndpoints"),
        ApplicationContextAware {

    val log = LoggerFactory.getLogger(ShowEndpoints::class.java)
    private var applicationContext: ApplicationContext? = null

    @Throws(BeansException::class)
    override fun setApplicationContext(applicationContext: ApplicationContext) {
        this.applicationContext = applicationContext
    }
    ...
}

Spring容器会检测容器中的所有Bean,如果发现某个Bean实现了ApplicationContextAware接口,Spring容器会在创建该Bean之后,自动调用该Bean的setApplicationContextAware()方法,将容器对象本身作为applicationContext实例变量参数传给该方法。
接下来可以通过该applicationContext实例变量来访问容器本身。使用ApplicationContext对象调用getBeansOfType(Class<T> type) 获取当前 Spring Boot 应用程序中所有的 Endpoint 接口类型和MvcEndpoint接口类型的 Bean。相关代码是:

val endpoints = this.applicationContext?.getBeansOfType(Endpoint::class.java)
val mvcEndpoints = applicationContext?.getBeansOfType(MvcEndpoint::class.java)

完整的实现代码可以参看示例工程源代码.kt。在ShowEndpoints.kt 中,可以参考实例工程源代码。
1.4.4 实现健康指标接口HealthIndicator
下面我们在 /health端点中自定义健康信息myCustome,输出的数据如下:

我们只需要实现HealthIndicator接口即可。HealthIndicator接口协议如下

package org.springframework.boot.actuate.health;
public interface HealthIndicator {
    Health health();
}

具体的实现代码如下

@Component
class MyCustomHealthIndicator : HealthIndicator {

    override fun health(): Health {
        val errorCode = check() // 健康检查方法示例
        return if (errorCode != 0) {
            Health.down().withDetail("Error Code", errorCode).build()
        } else Health
                .up()
                .withDetail("imageRepository.selectTest", errorCode)
                .build() // 返回selectTest健康信息
    }

    @Autowired lateinit var imageRepository: ImageRepository
    // 健康检查方法逻辑
    private fun check(): Int {
        return imageRepository.selectTest()
    }
}

其中,imageRepository.selectTest()方法代码是

@Query(value = "select 0", nativeQuery = true)
fun selectTest():Int

1.4.5 实现度量指标接口PublicMetrics

Actuator 中提供的PublicMetrics接口实现类有

...

本节 Spring Boot客户端应用源代码:https://github.com/AK-47-D/cms-spider/tree/boot_admin_2018.2.4

Spring Boot Admin Server 工程源代码:
https://github.com/KotlinSpringBoot/demo_boot_admin

1.6 本章小结

Spring Boot Actuator 提供了强大的应用自省功能,提供了丰富的 Endpoints 的信息覆盖 Spring Boot 应用程序运行的方方面面。同时,结合可视化的 Spring Boot Admin 管理界面,一切显得如此“高大上”。而在此过程中,我们只需要极简的几步配置即可完成这些事情。这正是 Spring Boot 的“初心” 所在。
下章介绍 Spring Boot 应用的测试与部署。

新书上架:《Spring Boot 开发实战》

— 基于 Kotlin + Gradle + Spring Boot 2.0 的企业级服务端开发实战

京东下单链接

https://item.jd.com/31178320122.html

天猫下单链接

https://detail.tmall.com/item.htm?id=574928877711

新书上架:《Spring Boot 开发实战》

— 基于 Kotlin + Gradle + Spring Boot 2.0 的企业级服务端开发实战

京东下单链接

https://item.jd.com/31178320122.html

天猫下单链接

https://detail.tmall.com/item.htm?id=574928877711

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容