YMNNALFT:使用 Micrometer 积累维度指标

工程 | Josh Long | 2021 年 1 月 20 日 | ...

欢迎阅读《你可能不需要另一个库》(You May Not Need Another Library For That) (YMNNALFT) 系列的又一篇!自 2016 年以来,我在我的 Spring Tips 视频中花费了大量时间阐明(或者至少是尝试阐明!)Spring 生态系统中一些巨大的机遇。然而,今天我怀着不同的心情与大家见面,想要关注那些有时隐藏着的小宝石,它们能做很棒的事情,也许可以让你免去额外引入第三方依赖及其带来的复杂性。

凌晨 3 点了。你知道你的生产环境 KPI 指标在哪里吗?无法衡量的东西就无法改进,而指标是其中的重要组成部分。没有指标,我们将彻底、绝望地迷失方向,陷入螺旋式下降的死亡行军项目,看不到任何改进的迹象或希望!颤抖吧,你们这些可怜而悲惨的开发者!没有指标,我们就像瞎子一样,这可一点都不好笑,所以这里放一张我女儿可爱的小豚鼠 Kai 的照片作为替代。

指标为我们提供了一种描述系统特定事实的方式——它允许我们量化重要数据,这很好,因为有各种各样的事情需要计数和量化。

  • 有多少人点击了‘结账’按钮?
  • 有多少人注册了?
  • 对特定端点的请求需要多长时间?
  • 有多少人遇到了错误?
  • 给定请求的平均时间是多少?(或者,更有用地,给定请求的第 99 百分位是多少?)
  • Bob,你把你的 TPS 报告交了吗?哦,快点,Bob!我们谈过这个了!你说过周二下班前会交的,你这个彻头彻尾的坏蛋!

学习捕捉哪些指标以及哪些是无关紧要的,这真是一门艺术。甚至可以成为一项职业!有人想成为“增长黑客”吗?并非所有指标都同等重要。增长黑客关心指标。产品经理会关心指标。业务部门会关心指标。你的平台可以关心指标。应该关心指标。为什么不呢?所有数据都唾手可得,但你需要一个强大的框架来帮助你。编写代码来度量你的代码并捕获指标只是战斗的一半。一旦捕获,你会想要(需要!)存储和分析这些指标。为此,你将使用时间序列数据库(Time Series Database,TSDB)——比如VMWare 的 WavefrontPrometheusNetflix AtlasDataDogInstana 等,然后可视化和分析这些数据。你需要一个强大的框架,支持在各种上下文中捕获各种类型的指标(计时器、计数器、直方图、平均值等),然后将这些指标发送到各种时间序列数据库(TSDB)。

Micrometer 应运而生。Micrometer 允许你使用供应商中立的接口,通过维度指标来度量你的代码,并在最后一步决定你想使用哪种监控系统。使用 Micrometer 对核心库代码进行度量,使得这些库可以包含在将指标发送到不同后端的应用中。Spring Boot 提供了 Actuator 模块,用于支持捕获和观察应用的不同方面。它提供了各种端点,例如应用健康、线程 dump 等等。它有一个端点 /actuator/metrics,该端点依赖于 Micrometer,即使你没有将这些指标发布到 TSDB,它也能让你一目了然地查看 Spring Boot 应用捕获的指标。

请记住,Spring 依赖于 Micrometer,但 Micrometer 不依赖于 Spring。许多库使用 Micrometer SPI 来实现自身度量。你所需要做的就是添加与 TSDB 的集成。以下是一些使用 Micrometer 发送指标的第三方库:Javalin、HikariCP、RabbitMQ Java 客户端、Redisson、Brave 分布式跟踪客户端、Netflix Spinnaker、基于 Netty 的非阻塞 Armeria 框架、阿里巴巴 Nacos 客户端、Apache Geode、Microsoft Azure Spring Boot 集成、Resilience4J、响应式 Playtika Feign 客户端、Openrewrite、Apache Camel、Couchbase Java DCP 客户端,以及数百个其他库。哦,我有没有提到 Spring 生态系统中的无数模块也支持它?是的,Micrometer 确实无处不在!

我们当然使用的是 Spring,因此最简单的方法就是将 Spring Boot Actuator 模块添加到构建中。如果你想支持特定的 TSDB,你需要引入针对该特定集成的模块。一些 Micrometer 集成也提供了完整的 Spring Boot 集成,所以如果你愿意,可以使用它们来代替直接的 Micrometer 集成。VMware Wavefront 就是这样一个 TSDB,它提供了广泛而丰富的 Spring Boot 集成,因此我将在这里引入这个超集集成。

我们来看一个简单的服务。

你需要以下依赖项。

  • Spring Initializr 上的 Actuator (Spring Initializr) - org.springframework.boot : spring-boot-starter-actuator

  • Spring Initializr 上的 Wavefront (Spring Initializr) - com.wavefront : wavefront-spring-boot-starter

在这个例子中,我创建了两个计数器指标,用于统计我当天的咖啡消耗量。我为数据添加了一个额外的维度:咖啡是否含有咖啡因。

代码如下

package bootiful.metrics;

import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;

import java.time.Duration;
import java.util.concurrent.TimeUnit;

@SpringBootApplication
public class BootifulApplication {

	public static void main(String[] args) {
		System.setProperty("spring.profiles.active", "metrics");
		SpringApplication.run(BootifulApplication.class, args);
	}

	@Bean
	ApplicationListener<ApplicationReadyEvent> ready(MeterRegistry registry) {
		return event -> {

			// http://localhost:8080/actuator/metrics/coffees
			String metricsKey = "coffees";
			Counter decaffeinated = registry.counter(metricsKey, "caffeine", "false");
			Counter caffeinated = registry.counter(metricsKey, "caffeine", "true");

			for (int i = 0; i < (int) (Math.random() * 10); i++)
				caffeinated.increment();

			for (int i = 0; i < (int) (Math.random() * 10); i++)
				decaffeinated.increment();

			System.out.println("caffeinated: " + caffeinated.count());
			System.out.println("decaffeinated: " + decaffeinated.count());

			// http://localhost:8080/actuator/metrics/message-print
			Timer timer = registry.timer("message-print");

			for (int i = 0; i < 10; i++)
				timer.record(Duration.ofMillis((long) (Math.random() * (10 * 1000))));

			System.out.println("message-print: " + timer.totalTime(TimeUnit.SECONDS));
		};
	}

}

这是我放入 application.properties 的内容

spring.main.web-application-type=reactive
management.endpoints.web.exposure.include=*
management.endpoint.metrics.enabled=true

在本系列的多数文章中,我都会提及正在讨论的库的可能替代方案。但在这里我不想这样做,因为我还没有真正找到能与 Micrometer 媲美的任何东西,如果我说找到了,那将是不真诚的。Micrometer 是一个更好的解决方案。你找到的大多数其他指标框架要么无法像 Micrometer 那样与众多解决方案集成,要么更糟糕的是,不支持维度指标。维度指标是指附带有多种属性(维度)的指标数据。这些属性可以包括与持续时间相关的属性(开始时间和停止时间)、ID、与客户端上下文相关的元数据、请求的区域、有关客户端的信息、有关被调用的端点的信息、主机、状态码等。如此详细的信息有助于进行深入的分析和查询。维度指标意味着更容易捕获指标,并且以后也更容易以意想不到的方式深入研究这些指标。双赢!

你喜欢这种对亮点一览无余的方法吗?你学到了什么吗?一如既往,我非常想听听你的想法,所以请在 Twitter 上畅所欲言 (@starbuxman) !我将带来 YMNNALFT 系列的下一篇,所以务必不要错过。

订阅 Spring 通讯

订阅 Spring 通讯,保持联系

订阅

提升自己

VMware 提供培训和认证,助你加速进步。

了解更多

获取支持

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件,只需一份简单订阅即可获得。

了解更多

即将举行的活动

查看 Spring 社区所有即将举行的活动。

查看全部