在微服务架构中,我们将原本庞大的单体系统拆分成多个提供不同服务的应用。 虽然 各个应用的内部逻辑因分解而得以简化,但是由于部署应用的数量成倍增长,使得系统的 维护复杂度大大提升。 对于运维人员来说,随着应用的不断增多,系统集群中出现故障的 频率也变得越来 越高,虽然在高可用机制的保护下,个别故障不会影响系统的对外服务, 但是这些频繁出现的故障需要被及时发现和处理才能长期保证系统处千健康可用状态。 为 了能对这些成倍增长的应用做到高效运维,传统的运维方式显然是不合适的,所以我们需 要实现一套自动化的监控 运维机制,而这套机制的运行基础就是不间断地收集各个微服务 应用的各项 指标情况,并根据这些基础指标信息来制定监控和预警规则,更进一步甚至做 到一些自动化的运维操作等。
为了让运维系统能够获取各个微服务应用的相关指标以及实现一些常规操作控制,我 们需要开发一套专门用于植入各个微服务应用的接口供监控 系统采集信息。 而这些接口往 往有很大一 部分指标都是类似的, 比如环境变量、 垃圾收集信息、 内存信息、 线程池信息 等。 既然这些信息那么通用,难道就没有一个标准化的实现框架吗?
当我们决定用Spring Boot来作为微服务框架时,除了它强大的快速开发功能之外,还因 为它在Starter POMs中提供了一个特殊依赖模块spring-boot-starter-actuator 。引入该模块能够自动为 Spring Boot 构建的应用提供 一系列用千监控的端点。 同时, Spring Cloud 在实现各个微服务组件的时候, 进 一步为该模块做了不少扩展, 比如, 为原生端点 增加了更多的指标和度量信息(比如在整合 Eureka 的时候会为/health 端点增加相关的 信息), 并且根据不同的组件还提供了更多有空的端点(比如, 为 API 网关组件 Zuul 提供 了 /routes 端点来返回路由信息)。
spring-boot-starter-actuator 模块的实现对千实施微服务的中小团队来说, 可以有效地省去或大大减少监控系统在采集应用指标时的开发量。 当然, 它也并不是万能 的, 有时候也需要对其做 一些简单的扩展来帮助我们实现自身系统个性化的监控需求。 所 以,在本节将详细介绍一些关于spring-boot-starter-actuator模块的内容, 包括 原生提供的端点以及一些常用的扩展和配置方式等。
在现有 的 Spring Boot 应用中引入该模块非常简单 , 只需要 在 pom.xml 的 dependency 节点中,新增 spring-boot-starter-actua七or 的依赖即可,具体如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
增加该依赖之后,重新启动应用。此时,我们可以在控制台中看到如下图所示的输出:
: Mapped "{[/trace i I /trace.json],methods=(GET),produces=[applicat10n
: Mapped "{[/info 11 /info.json],methods=[GET},produces=[application/j
: Mapped " { [ / env / {name: , •}], methods=[ GET), produces= [ application/json)}
: Mapped "{[/env 11 /env.json],methods=[GET),produces=[application/jso
: Mapped "{[/dump 11 /dump.json],methods=[GET),produces=[application/j, Mapped "([/autoconfig 11 /autoconfig.json],rnethods=[GET),produces=[a
: Mapped "{[/health 11 /health.json],produces=[application/json)}" ont
: Mapped "{[/mappings 11 /mappings.json],methods=(GET],produces=(appli
: Mapped "{[/beans 11 /beans.json],methods=[GET),produces=[application
: Mapped "{[/configprops 11 /configprops.json],methods=[GET),produces=
: Mapped "{[/metrics/{name:. 不}],methods=(GET),produces=[application/js
: Mapped "{[/metrics 11 /metrics.json],methods=[GET),produces=(applica
原生端点
通过在快速入门示例中添加spring-boot-starter-actuator模块, 我们已经对 它有了 一个初步的认识。接下来,我们详细介绍一下 spring-boot-starter-actuator模块中已经实现的一些原生端点。 根据端点的作用, 可以将原生端点分为以下三大类。
• 应用配置类:获取应用程序中加载的应用配置、 环境变量、 自动化配置报告等与 Spring Boot应用密切相关的配置类信息。
• 度最指标类:获取应用程序运行过程中用于监控的度量指标, 比如内存信息、 线程 池信息、 HTTP请求统计等。
• 操作控制类:提供了对应用的关闭等操作类功能。
应用配置类->由于SpringBoot为了改善传统Spring应用繁杂的配置内容,采用了包扫描和自动化配 置的机制来加载原本集中于XML文件中的各项内容。 虽然这样的做法让我们的代码变得 非常简洁,但是整个应用的实例创建和依赖关系等信息都被离散到了各个配置类的注解上, 这使我们分析整个应用中资源和实例的各种关系变得非常困难。 而这类端点可以帮助我们 轻松获取一系列关于 Spring 应用配置内容的详细报告, 比如自动化配置的报告、 Bean创 建的报告、 环境属性的报告等。
/autoconfig:该端点用来获取应用的自动化配置报告, 其中包括所有自动化配置的 候选项。 同时还列出了每个候选项是否满足自动化配置的各个先决条件。 所以, 该 端点可以帮助我们方便地找到一些自动化配置为什么没有生效的具体原因。 该报告 内容将自动化配置内容分为以下两部分。
positiveMatches中返回的是条件匹配成功的自动化配置。
negativeMatches中返回的是条件匹配不成功的自动化配置。
/beans:该端点用来获取应用上下文中创建的所有Bean。
Bean 中都包含了下面这些信息:
• bean: Bean 的名称。
• scope: Bean 的作用域。
• type: Bean 的 Java 类型。
• resource: class 文件的具体路径。
• dependencies: 依赖的 Bean 名称。
/configprops:该端点用来获取应用中配置的属性信息报告。 从下面该端点返回示例 的片段中, 我们看到返回了关于该短信的配置信息, prefix 属性代表了属性的配 置前缀, properties 代表了各个属性的名称和值。 所以, 我们可以通过该报告来 看 到各个属性的 配 置路 径, 比如我们要关闭该端点, 就可 以 通过使用 endpoints.configprops.enabled=false 来完成设置。
/env: 该端点与/configprops不同它用来获取应用所有可用的环境属性报告。 包括 环境变量、NM属性、应用的配置属性、命令行中的参数。 从下面该端点返回的示 例片段中, 可以看到它不仅返回了应用的配置属性, 还返回了系统属性、环境变量 等丰富的配置信息, 其中还包括了应用还没有使用的配置, 所以它可以帮助我们方 便地看到当前应用可以加载的配置信息, 并配合@ConfigurationProperties 注解将它们引入到我们的应用程序中来进行使用。 另外, 为了配置属性的安全, 对 于一些类似密码等敏感信息, 该端点都会进行隐私保护, 但是我们需要让属性名中 包含password、secret、key这些关键词, 这样该端点在返回它们的时候会使用*来替代实际的属性值。
/mappings: 该端点用来返回所有Spring MVC的控制器映射关系报告。 从下面的示 例片段中, 我们可以看到该报告的信息与我们在启用Spring MVC的Web应用时输 出的日志信息类似, 其中bean属性标识了该映射关系的请求处理器, method属 性标识了该映射关系的具体处理类和处理函数。
/info: 该端点用来返回一些应用自定义的信息。 默认清况下, 该瑞点只会返回 一个 空的JSON内容。我们可以在application.properties配置文件中通过info 前缀来设置一些属性, 比如下面这样: info.app.name=spring-boot-hello
info.app.version=vl.0.0
再访问/info端点我们可以得到下面的返回报告, 其中就包含了上面我们在应用 中自定义的两个参数。
"app": {
"name": "spring-boot-hello",
"version": "vl.0.0"
}
2、度量指标类-->上面我们所介绍的应用配置类端点所提供的信息报告在应用启动的时候就已经基本确 定了其返回内容, 可以说是一个静态报告。 而度量指标类端点提供的报告内容则是动态变 化的,这些端点提供了应用程序在运行过程中的一些快照信息,比如内存使用情况、 HTTP 请求统计、外部资源指标等。这些端点对于我们构建微服务架构中的监控系统非常有帮助, 由于 Spring Boot 应用自身实现了这些端点,所以我们可以很方便地利用它们来收集我们想 要的信息, 以制定出各种自动化策略。
/metrics: 该端点用来返回当前应用的各类重要度量指标,比如内存信息、线程信息、 垃圾回收信息等。
{
"mem":1292717,
"mem.free":703542,
"processors":32,
"instance.uptime":245161086,
"uptime":245165938,
"systemload.average":0,
"heap.committed":1238016,
"heap.init":1026744,
"heap.used":534473,
"heap":14603776,
"nonheap.committed":55232,
"nonheap.init":24000,
"nonheap.used":54701,
"nonheap":133120,
"threads.peak":28,
"threads.daemon":23,
"threads.totalStarted":296,
"threads":26,
"classes":8854,
"classes.loaded":8854,
"classes.unloaded":0,
"gc.ps_scavenge.count":4,
"gc.ps_scavenge.time":163,
"gc.ps_marksweep.count":0,
"gc.ps_marksweep.time":0,
"httpsessions.max":-1,
"httpsessions.active":0,
"counter.status.200.aliPay.createOrderANdAliPayUrl":4,
"counter.status.200.aliPay.notifyUrl":2,
"counter.status.200.atOnceWithhold":12,
"counter.status.200.autoconfig":1,
"counter.status.200.metrics":1,
"counter.status.200.withhold":254,
"counter.status.405.unmapped":2,
"gauge.response.aliPay.createOrderANdAliPayUrl":35,
"gauge.response.aliPay.notifyUrl":481,
"gauge.response.atOnceWithhold":10046,
"gauge.response.autoconfig":35,
"gauge.response.metrics":19,
"gauge.response.unmapped":6,
"gauge.response.withhold":16
}
从上面的示例中, 我们看到有如下这些重要的度量值。
• 系统信息:包括处理器数量processors、运行时间up巨me和instance.uptime、 系统平均负载 systemload.average。
• mem. *: 内存概要信息,包括分配给应用的总内存数量以及当前空闲的内存数量。 这些信息来自java.lang.Runtime。
• heap.* : 堆内存使用情况。 这些信息来自 java.lang.management. MemoryMXBean 接口中 getHeapMemoryUsage 方法获取的 java.lang. management.MemoryUsage。
• nonheap. *: 非堆内存使用情况。 这些信息来自 java. lang.management. MemoryMXBean接口中getNonHeapMemoryUsage方法获取的java.lang. managemen.MemoryUsage。
• threads.*: 线程使用情况,包括线程数、守护线程数(daemon)线程峰值(peak) 等, 这些数据均来自java.lang.management.ThreadMXBean。
• classes.*: 应用加载和卸载的类统计。这些数据均来自java.lang.managemen七. ClassLoadingMXBean。
• gc. *: 垃圾收集器的详细信息,包括垃圾回收次数gc.ps—scavenge.coun七、 垃圾回收消耗时间 gc.ps_scavenge.time、 标记-清除算法的次数 gc.ps marksweep.count、 标记-清除算法的消耗时间gc.ps_marksweep.time。 这些数据均来自java.lang.managemen.GarbageCollectorMXBean。
• httpsessions. * : Tomcat容 器 的会话使用情况。 包 括最大会话 数 httpsessions.max和活跃会话数httpsessions.ac巨ve。 该度量指标信 息仅在引入嵌入式Tomcat作为应用容器的时候才会提供。
• gauge.*: HTTP请求的性能指标之一,它主要用来反映一个绝对数值。 比如上 面示例中的gauge.response.hello: 5, 它表示上 一 次hello请求的延迟 时间为5毫秒。
• counter.*: HTTP 请求的性能指标之一,它主要作为计 数器来使用,记录了 增加量和减少量。 上述示例中的counter.status.200.hello: 11, 它代表 了 hello请求返回200状态的次数为11。
/metrics端点可以提供应用运行状态的完整度量指标报告,这项功能 非常实用,但是 对千监控系 统中的各项监控功能,它们的监控内容、 数据收集频率都有所不同,如 果每次都通过全量获取报告的方式来收集,略显粗暴。 所以,我们还可以通过 /metrics/{name}接口来更细粒度地获取度量信息 , 比 如可 以通 过访 问 /metrics/mem.free来获取当前可用 内存数量。
curl -i http://****:8081/metrics/mem.free
{
"mem.free":1447714
}
/health: 该端点在一开始的示例中 我们已经使用过了,它用来获取应用的各类 健康 指标信息。在spring-boot-starter-actuator模块中自带实现了 一些常用资 源的健康指标检测器。这些检测器 都通过Hea巨hindicator接口实现,并且会根 据依赖关系的引入实现自动化装配,
检测器 功能
DiskSpaceHealthlndicator 低磁盘空间检测
DataSourceHealthlndicator 检测DataSource的连接是否可用
MongoHealthlndicator 检测Mango数据库是否可用
RabbitHealthlndicator 检测Rabbit服务器是否可用
RedisHealthlndicator 检测Redis服务器是否可用
SolrHealthlndicator 检测Solr服务器是否可用
/dump: 该端点用来暴露程序运行中的线程信息。它使用 java.lang.managerment.ThreadMXBean 的 durnpAllThreads方法来返回所有含有同步信息的活动线程详 情。
/trace: 该端点用来返回基本的 HTTP 跟踪信息。 默认情况下, 跟踪信息的存储采用 org.springfrarnework.boo七.ac七uate.trace.InMernoryTraceRepository 实现的内存方式, 始终保留最近的100条请求记录。 它记录的内容格式如下所示:
3、操作控制类-->在原生端点中, 只提供了一个用来关闭应用的端点: /shutdown (在后续我们引入了 Eureka之后, 会引入更多控制端点)。 可以通过如下配置开启它: endpoints.shutdown.enabled=true
在配置了上述属性之后,只需要访问该应用的/shutdown端点就能实现关闭该应用的 远程操作。 由于开放关闭应用的操作 本身是一 件非常危险的事, 所以真正在线上使用的时候,需要对其加入一定的保护机制, 比如定制actuator的端点路径、整合SpringSecurity进行安全校验等,稍后讲解Spring Cloud Eureka 微服务架构中的服务治理在进行扩展。