领先一步
VMware 提供培训和认证,以加快您的进步。
了解更多目录
Micrometer 是一个维度优先的指标收集外观,其目标是允许您使用与供应商无关的 API 来计时、计数和衡量您的代码。通过类路径和配置,您可以选择一个或多个监控系统来导出您的指标数据。可以把它想象成 SLF4J,但用于指标!
Micrometer 是 Spring Boot 2 的 Actuator 中包含的指标收集工具。它还已向后移植到 Spring Boot 1.5、1.4 和 1.3,只需添加另一个依赖项。
Micrometer 为 Spring Boot 1 中存在的计数器和量规添加了更丰富的计量原语。例如,单个 Micrometer Timer
能够生成与吞吐量、总时间、最近样本的最大延迟、预计算百分位数、百分位数直方图和 SLA 边界计数相关的时序数据。
尽管 Micrometer 侧重于维度指标,但它确实映射到分层名称,以继续为 Ganglia 等较旧的监控解决方案或 JMX 等范围较窄的工具提供服务。对 Micrometer 的更改源于希望更好地服务于一波维度监控系统(例如 Prometheus、Datadog、Wavefront、SignalFx、Influx 等)。Spring 的优势之一是通过抽象实现选择。通过与 Micrometer 集成,Spring Boot 使您能够选择一个或多个监控系统在今天使用,并在您的需求改变时以后改变主意,而无需重写您的自定义指标检测。
在选择开发“另一个”指标收集库之前,我们仔细研究了现有或即将推出的维度收集器。但是,当我们查看向越来越多的监控系统导出数据时,名称和数据的结构的重要性变得显而易见。Micrometer 内置了命名约定规范化、时间基本单位缩放以及对直方图数据等结构的专有表达的支持,这些对于使指标在每个目标系统中都能脱颖而出至关重要。在此过程中,我们还添加了指标过滤,允许您更好地控制上游依赖项的检测。
提示
要了解 Micrometer 的更多功能,请参阅其参考文档,尤其是概念部分。
Spring Boot 2 自动配置了许多指标,包括:
JVM,报告使用情况:
各种内存和缓冲池
与垃圾收集相关的统计信息
线程使用情况
已加载/卸载的类数
CPU 使用率
Spring MVC 和 WebFlux 请求延迟
RestTemplate 延迟
缓存使用情况
数据源使用情况,包括 HikariCP 池指标
RabbitMQ 连接工厂
文件描述符使用情况
Logback:记录每个级别记录到 Logback 的事件数
运行时间:报告运行时间的量规和表示应用程序绝对启动时间的固定量规
Tomcat 使用情况
Spring Boot 1 中以某种形式存在许多这些指标,但在 Spring Boot 2 中已通过更详细的信息和标签进行了丰富。
Micrometer 提供了一个与供应商无关的指标收集 API(根植于io.micrometer.core.instrument.MeterRegistry
)以及针对各种监控系统的实现
Netflix Atlas
CloudWatch
Datadog
Ganglia
Graphite
InfluxDB
JMX
New Relic
Prometheus
SignalFx
StatsD(Etsy、dogstatsd、Telegraf 和专有格式)
Wavefront
正在开发或计划在 2018 年年中发布的 1.1.0 版本中支持其他系统
AppOptics
Azure Application Insights
Dynatrace
Elasticsearch
StackDriver
Spring Boot 2 配置了一个复合MeterRegistry
,可以向其中添加任意数量的注册表实现,允许您将指标发送到多个监控系统。通过MeterRegistryCustomizer
,您可以自定义整套注册表或特定个别实现。例如,一个常用的设置是:(1)将指标导出到 Prometheus 和 CloudWatch;(2)向流向两者的指标添加一组公共标签(例如,主机和应用程序标识标签);(3)仅将一小部分指标列入 CloudWatch 的白名单。
指标特指允许您推断系统整体性能(跨单个应用程序的不同组件、集群中的实例、在不同环境或区域中运行的集群等)的信息类别。
值得注意的是,这排除了旨在推断各个组件对单个请求在其穿过一系列服务时总延迟的贡献的信息;这是分布式跟踪收集器(如Spring Cloud Sleuth、Zipkin 的Brave等)的职责。
分布式跟踪系统提供有关子系统延迟的详细信息,但通常会进行下采样以进行扩展(例如,Spring Cloud Sleuth 默认情况下会发送 10% 的样本)。指标数据通常是预先聚合的,因此自然缺乏相关信息,但也没有下采样。因此,对于在一分钟间隔内具有 100,000 个请求的序列,这些请求具有与服务 A 的交互,并且根据输入,可能与服务 B 的交互
指标数据会告诉您,总体而言,服务 A 的观察到的吞吐量为 100k 个请求,服务 B 的观察到的吞吐量为 60k 个请求。此外,在那分钟内,服务 A 的最大总体平均延迟为 100 毫秒,服务 B 的最大总体平均延迟为 50 毫秒。它还将提供有关该期间最大延迟和其他分布统计信息。
分布式跟踪系统会告诉您,对于特定请求(但不是整个请求群,因为请记住正在进行下采样),服务 A 耗时 50 毫秒,服务 B 耗时 90 毫秒。
您可以合理地从指标数据推断出,在最坏情况下的用户体验中,大约一半的时间都花在了 A 和 B 的每一个上,但您不能确定,因为您正在查看聚合数据,并且在最坏情况下,所有 100 毫秒都可能花在了服务 A 上,而根本没有调用服务 B。
相反,从跟踪数据中,您无法推断一段时间内的吞吐量或最坏情况下的用户体验。
Spring Boot 1 的指标接口本质上是分层的。这意味着已发布的指标完全由其名称标识。因此,您可能有一个名为jvm.memory.used
的指标。
当您查看来自单个应用程序实例的指标时,这似乎很合适。但是,如果您有 10 个实例都将jvm.memory.used
发布到同一个监控系统,会发生什么情况?如果某个实例上的内存消耗意外激增,我们如何区分它们?
通常的做法是在名称中添加内容,例如添加前缀或后缀。因此,我们可以将名称更改为${HOST}.jvm.memory.used
,其中我们将${HOST}
替换为主机名。重新部署所有10个实例后,我们现在可以识别哪个实例处于内存压力之下。在一个典型的分层监控系统中,我们可以通过某种方式使用通配符来推断所有实例使用的内存总和。
*.jvm.memory.used
现在假设我们在3个部署区域中各有10个应用程序实例。此外,我们希望根据区域推断应用程序的平均或最大内存占用量。现在,如果我们在指标名称中添加另一个前缀(使其看起来像${REGION}.${HOST}.jvm.memory.used
),我们将破坏现有的查询。我们可以更新查询以推断所有实例使用的内存总和。
*.*.jvm.memory.used
不幸的是,这会使我们现有的基础设施失明,直到所有基础设施都重新部署了新的前缀。这只是一个分层命名方法的一个局限性的例子。
我们前面已经提到,Micrometer是一个维度优先的指标收集器。在 Micrometer 中,相同的指标将使用标签(又名维度)进行记录。
Gauge.builder("jvm.memory.used", ..)
.tag("host", "MYHOST")
.tag("region", "us-east-1")
.register(registry);
维度监控系统自然会在所有标签的聚合中显示jvm.memory.used
,直到您深入研究其中一个或多个标签为止。维度监控系统中的查询将首先选择名称(jvm.memory.used
),并允许随后按标签进行过滤。在我们上面的场景中,如果我们有一个基于主机内存消耗激增的现有图表/警报,然后之后为区域添加了额外的标签,则基于主机的查询将继续不间断地工作,因为新的包含区域的指标会在您的基础设施中推出。
指标过滤器允许您控制何时以及如何注册指标以及它们发出哪种类型的统计信息。指标过滤器具有三个基本功能:
拒绝(或接受)注册指标。
转换指标 ID(例如更改名称、添加或删除标签、更改描述或基本单位)。
配置某些指标类型的分布统计信息(例如,百分位数、直方图、计时器和分布摘要的 SLA)。
Spring Boot 2 将一系列属性绑定到开箱即用的指标过滤器,允许您通过属性控制指标发射。例如:
management.metrics.enable.jvm=false
management.metrics.distribution.percentiles-histogram.http.server.requests=true
management.metrics.distribution.sla.http.server.requests=1ms,5ms
以上操作关闭所有以“jvm”为前缀的指标,发布 Spring Boot 自动配置的 http 服务器请求指标的百分位数直方图,并发送小于或等于 1ms 和 5ms SLA 边界的请求计数,以便您可以准确查看有多少请求满足您的期望。SLA 分布配置也是使您能够可视化更复杂的测量(如Apdex 分数)的核心功能。
您可以完全翻转指标的启用状态以生成仅包含您想要的一小部分指标的白名单。假设您只想要 JVM 指标:
management.metrics.enable.all=false
management.metrics.enable.jvm=true
在 Spring Boot 1 中提供单个列出所有指标的 REST 端点非常简单,因为我们只有计数器和仪表,而且两者都是分层的。更复杂的类型(如计时器)表示多个时间序列(它们至少包含计数、最大值和总和)。此外,我们的指标也变成了维度化的。很快就很清楚,无法在单个有效负载中输出所有这些信息。即使对于维度计数器,我们是否要显示每个标签排列的聚合?为了简洁起见,扁平化到分层名称,这将变成:
http.server.requests.method.GET.response.200.uri./foo=100
http.server.requests.method.GET.response.500.uri./foo=1
http.server.requests.method.GET.response.200.uri./bar=5
http.server.requests.method.GET.response.400.uri./foo=1
# and now the aggregates...
http.server.requests.method.GET=107
http.server.requests.method.GET.response.200=105
http.server.requests.method.GET.uri./foo=101
http.server.requests.response.200.uri./foo=100
http.server.requests.response.500.uri./foo=1
http.server.requests.response.200.uri./bar=5
...
如您所见,这很快就会变得难以维护。例如,如果您想基于MeterRegistry
的内容构建自定义 UI,并且您知道您的 UI 只对每个 URI 的 http 吞吐量感兴趣,而与方法、状态等无关,则输出可以大大缩减。对于这些情况,我们建议创建一个组件,仅向您的 UI 提供它所需的数据。将MeterRegistry
注入到您的组件中,并使用它的find
和get
方法来搜索您需要公开的指标。然后以适合您使用的格式对其进行序列化。
Micrometer 支持可在 slack 上获得:slack.micrometer.io,在 Twitter 上@micrometerio,以及在Github上。如有任何疑问、建议或问题,请随时联系我们!