我们正在使用 Quarkus Jakarta 构建一个自定义的 Prometheus 导出器,重点是避免高基数并确保高效的指标。准备好迎接一些指标魔法吧!
为什么要自定义导出器?我们不是在重新发明轮子吗?
在深入探讨之前,让我们先解决一个问题:为什么要费心自定义导出器,而不是使用现成的解决方案?
- 定制化指标:您的应用程序是独特的,有时您需要的指标并不是现成的。
- 性能优化:自定义导出器可以让您微调测量内容,可能减少开销。
- 避免指标爆炸:强大的能力伴随着巨大的责任——以及避免高基数陷阱的能力。
设置 Quarkus Jakarta 项目
首先,让我们启动并运行我们的 Quarkus 项目。如果您是 Quarkus 的新手,可以将其视为 Jakarta EE 的超级英雄版本——比子弹还快,比火车还强大。
使用以下 Maven 命令创建一个新的 Quarkus 项目:
mvn io.quarkus:quarkus-maven-plugin:2.16.5.Final:create \
-DprojectGroupId=com.example \
-DprojectArtifactId=custom-prometheus-exporter \
-DclassName="com.example.ExporterResource" \
-Dpath="/exporter"
现在,让我们将必要的依赖项添加到我们的 pom.xml
中:
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-micrometer-registry-prometheus</artifactId>
</dependency>
</dependencies>
核心问题:构建导出器
现在我们已经设置好了项目,让我们创建我们的自定义导出器。我们将专注于一个假设场景,即我们正在监控一个复杂的电子商务系统。
package com.example;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tags;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import java.util.Random;
@Path("/exporter")
public class ExporterResource {
@Inject
MeterRegistry registry;
private final Random random = new Random();
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
// 模拟一些指标
recordOrderMetrics();
recordUserMetrics();
return "指标已更新!";
}
private void recordOrderMetrics() {
// 不记录每个产品的指标(高基数),
// 而是记录每个类别的汇总指标
String[] categories = {"Electronics", "Clothing", "Books", "Home"};
for (String category : categories) {
double orderValue = 100 + random.nextDouble() * 900; // 随机订单值在 100 到 1000 之间
registry.gauge("ecommerce.order.value", Tags.of("category", category), orderValue);
}
}
private void recordUserMetrics() {
// 不记录每个用户的指标,而是使用桶
int activeUsers = 1000 + random.nextInt(9000); // 随机数在 1000 到 10000 之间
String userBucket = activeUsers < 5000 ? "low" : "high";
registry.gauge("ecommerce.active.users", Tags.of("load", userBucket), activeUsers);
}
}
避免高基数陷阱
高基数是 Prometheus 设置中的噩梦。就像邀请您城市中的每个人参加家庭聚会——事情肯定会失控。以下是我们避免这种情况的方法:
- 分类:与其跟踪每个产品的指标(可能有数千个),不如将它们分组到类别中。
- 分桶:对于用户指标,我们使用简单的“低”或“高”桶,而不是单独跟踪每个用户。
记住,目标是拥有足够详细的信息以便有用,而不是淹没在数据中。
确保高效的指标
效率不仅仅是避免高基数。以下是一些保持指标精简的其他技巧:
- 谨慎使用标签:标签很强大,但如果使用过多,可能会导致指标爆炸。
- 尽可能汇总:有时总和或平均值比单个数据点更有用。
- 选择合适的指标类型:计量器、计数器和直方图各有其用途。明智地使用它们。
- 设置保留策略:并非所有指标都需要永久保留。在 Prometheus 中设置适当的保留期。
测试您的导出器
在我们自我表扬之前,让我们确保这个东西确实有效。运行您的 Quarkus 应用程序:
./mvnw quarkus:dev
现在,访问端点以生成一些指标:
curl http://localhost:8080/exporter
最后,查看您的指标:
curl http://localhost:8080/q/metrics
您应该会看到类似这样的内容:
# HELP ecommerce_order_value
# TYPE ecommerce_order_value gauge
ecommerce_order_value{category="Electronics"} 543.21
ecommerce_order_value{category="Clothing"} 321.54
ecommerce_order_value{category="Books"} 123.45
ecommerce_order_value{category="Home"} 987.65
# HELP ecommerce_active_users
# TYPE ecommerce_active_users gauge
ecommerce_active_users{load="high"} 7523.0
证据在于布丁:分析您的指标
现在我们已经启动并运行了导出器,让我们来谈谈可以用这些指标做些什么。以下是一些您可能会发现有用的 Prometheus 查询:
# 所有类别的平均订单值
avg(ecommerce_order_value)
# 活跃用户的总数
sum(ecommerce_active_users)
# 按类别的最高订单值
max(ecommerce_order_value) by (category)
这些查询让您了解从精心制作的指标中可以获得的见解。
总结:经验教训
构建自定义 Prometheus 导出器不仅仅是简单地组合一些指标然后就完事了。这是一门艺术,需要仔细考虑您正在测量的内容以及如何测量。以下是关键要点:
- 始终警惕高基数。它是 Prometheus 设置的无声杀手。
- 尽可能汇总和分类,以保持指标的意义和可管理性。
- 谨慎选择标签。它们很强大,但强大的能力伴随着巨大的责任。
- 测试、迭代和改进。您的第一次尝试可能不会完美,这没关系。
记住,目标是拥有提供可操作见解的指标,而不仅仅是一堆数字。祝您监控愉快!
思考的食粮
“计算的目标是洞察,而不是数字。” - Richard Hamming
当您继续完善自定义导出器时,请记住这句话。关键不在于您可以生成多少指标,而在于您可以从中获得多少见解。
附加资源
想深入了解?查看这些资源:
现在去像专业人士一样导出那些指标吧!记住,在监控的世界中,少即是多。除非我们在谈论正常运行时间——那时多就是多。