Prometheus Java 客户端指南

随着分布式系统变得越来越复杂,监控对于维护应用程序性能和快速识别问题变得至关重要。Prometheus是一个强大的开源监控和警报工具包,它是最好的工具之一。

Prometheus Java 客户端允许我们以最小的努力来检测我们的应用程序,通过向 Prometheus 公开实时指标以供抓取和监控。

在本文中,我们探讨了如何有效使用 Prometheus Java 客户端,通过检测自定义指标和 JVM 指标来监控应用程序。

  • 首先,我们介绍了如何使用 Maven 依赖项设置项目。
  • 随后,我们开始通过 HTTP 端点公开度量指标。
  • 随后,我们讨论了计数器、仪表盘、直方图和汇总表等关键指标类型,每种类型在跟踪各种性能指标方面都有不同的用途。

我们探索如何将 Prometheus Java 客户端库与 Maven 结合使用,包括创建自定义指标并配置 HTTP 服务器以公开这些指标。此外,我们还将介绍该库提供的不同指标类型,并提供将所有这些元素结合在一起的实际示例。

设置项目
要开始使用 Prometheus Java 客户端,我们将使用 Maven 来管理项目的依赖项。我们需要将几个基本依赖项添加到pom.xml文件中,以启用 Prometheus 指标收集和公开:

<dependency>
    <groupId>io.prometheus</groupId>
    <artifactId>prometheus-metrics-core</artifactId>
    <version>1.3.1</version>
</dependency>
<dependency>
    <groupId>io.prometheus</groupId>
    <artifactId>prometheus-metrics-instrumentation-jvm</artifactId>
    <version>1.3.1</version>
</dependency>
<dependency>
    <groupId>io.prometheus</groupId>
    <artifactId>prometheus-metrics-exporter-httpserver</artifactId>
    <version>1.3.1</version>
</dependency>

我们使用以下依赖项prometheus-metrics-core是 Prometheus Java 客户端的核心库。它为定义和注册自定义指标(如计数器、仪表、直方图等)提供了基础。

prometheus-metrics-instrumentation-jvm提供开箱即用的 JVM 指标,包括堆内存使用情况、垃圾收集时间、线程数等。

prometheus-metrics-exporter-httpserver提供了一个嵌入式 HTTP 服务器,用于以 Prometheus 格式公开指标。它创建了一个/metrics端点,Prometheus 可以抓取该端点来收集数据。

.创建并公开 JVM 指标
本节将介绍如何通过 Prometheus Java 客户端公开可用的 JVM 指标。这些指标为我们的应用程序性能提供了宝贵的见解。得益于prometheus-metrics-instrumentation-jvm依赖项,我们可以轻松注册开箱即用的 JVM 指标,而无需自定义检测:

public static void main(String[] args) throws InterruptedException, IOException {
    JvmMetrics.builder().register();
    HTTPServer server = HTTPServer.builder()
      .port(9400)
      .buildAndStart();
    System.out.println("HTTPServer listening on http://localhost:" + server.getPort() + "/metrics");
    Thread.currentThread().join();
}

为了让 JVM 指标可供 Prometheus 使用,我们通过 HTTP 端点公开了这些指标。我们使用prometheus-metrics-exporter-httpserver依赖项设置了一个简单的 HTTP 服务器,该服务器侦听端口并提供指标。

我们使用join()方法让主线程无限期地运行,确保 HTTP 服务器保持活动状态,以便 Prometheus 可以随着时间的推移持续抓取指标。

测试应用程序
应用程序运行后,我们可以打开浏览器并导航到http://localhost:9400/metrics来查看公开的指标,或者我们可以使用curl命令从命令行获取和检查指标:

$ curl http://localhost:9400/metrics

我们应该看到 Prometheus 格式的 JVM 相关指标列表,类似于:

# HELP jvm_memory_bytes_used Used bytes of a given JVM memory area.
# TYPE jvm_memory_bytes_used gauge
jvm_memory_bytes_used{area="heap",} 5242880
jvm_memory_bytes_used{area=
"nonheap",} 2345678
# HELP jvm_gc_collection_seconds Time spent in a given JVM garbage collector in seconds.
# TYPE jvm_gc_collection_seconds summary
jvm_gc_collection_seconds_count{gc=
"G1 Young Generation",} 5
jvm_gc_collection_seconds_sum{gc=
"G1 Young Generation",} 0.087
...

输出显示各种 JVM 指标,例如内存使用情况、垃圾收集详细信息和线程数。Prometheus 收集并分析这些指标,并将其格式化为其专用的展示格式。

指标类型
在 Prometheus Java 客户端中,指标分为不同类型,每种类型都有特定的用途,用于衡量应用程序行为的各个方面。这些类型基于Prometheus 遵循的OpenMetrics 标准。

让我们探索 Prometheus Java 客户端中可用的主要指标类型以及它们的通常使用方式。

计数器
计数器是一种随时间递增的指标。我们可以使用它们来计算收到的请求、遇到的错误或完成的任务。计数器不能减少,只有在进程重新启动时才会重置其值。

我们可以计算应用程序处理的 HTTP 请求总数:

Counter requestCounter = Counter.builder()
  .name("http_requests_total")
  .help(
"Total number of HTTP requests")
  .labelNames(
"method", "status")
  .register();
requestCounter.labelValues(
"GET", "200").inc();

我们使用labelNames和labelValues为指标添加维度或上下文。Prometheus 中的标签是键值对,可让我们区分同一指标的不同类别。

仪表
仪表是一种可以随时间增加或减少的指标。我们可以使用它们来跟踪随时间变化的值,例如内存使用量、温度或活动线程数。

为了测量当前内存使用情况或 CPU 负载,我们可能会使用一个仪表:

Gauge memoryUsage = Gauge.builder()
  .name("memory_usage_bytes")
  .help(
"Current memory usage in bytes")
  .register();
memoryUsage.set(5000000);

直方图
直方图通常用于观察和跟踪值随时间的变化,例如请求延迟或响应大小。它记录预先配置的存储桶,并提供有关每个存储桶中的观察次数、总数以及所有观察值总和的指标。这使我们能够了解数据分布并计算百分位数或范围。

让我们看一个详细的示例,该示例测量 HTTP 请求持续时间并使用自定义存储桶来跟踪特定范围的响应时间:

Histogram requestLatency = Histogram.builder()
  .name("http_request_latency_seconds")
  .help(
"Tracks HTTP request latency in seconds")
  .labelNames(
"method")
  .register();
Random random = new Random();
for (int i = 0; i < 100; i++) {
    double latency = 0.1 + (3 * random.nextDouble());
    requestLatency.labelValues(
"GET").observe(latency);
}

我们在创建直方图时没有指定任何自定义存储桶,因此库使用一组默认存储桶。默认存储桶涵盖指数范围的值,适合许多测量持续时间或延迟的应用程序。具体来说,默认存储桶边界如下:

[5ms, 10ms, 25ms, 50ms, 100ms, 250ms, 500ms, 1s, 2.5s, 5s, 10s, +Inf]

检查结果时我们可能会看到如下输出:

http_request_latency_seconds_bucket{method="GET",le="0.005"} 0
http_request_latency_seconds_bucket{method=
"GET",le="0.01"} 0
http_request_latency_seconds_bucket{method=
"GET",le="0.025"} 0
http_request_latency_seconds_bucket{method=
"GET",le="0.05"} 0
http_request_latency_seconds_bucket{method=
"GET",le="0.1"} 0
http_request_latency_seconds_bucket{method=
"GET",le="0.25"} 6
http_request_latency_seconds_bucket{method=
"GET",le="0.5"} 15
http_request_latency_seconds_bucket{method=
"GET",le="1.0"} 32
http_request_latency_seconds_bucket{method=
"GET",le="2.5"} 79
http_request_latency_seconds_bucket{method=
"GET",le="5.0"} 100
http_request_latency_seconds_bucket{method=
"GET",le="10.0"} 100
http_request_latency_seconds_bucket{method=
"GET",le="+Inf"} 100
http_request_latency_seconds_count{method=
"GET"} 100
http_request_latency_seconds_sum{method=
"GET"} 157.8138389516349

每个存储桶显示有多少观察结果落入该范围。例如,http_request_duration_seconds_bucket{le=”0.25″}显示 6 个请求所用时间小于或等于 250 毫秒。+Inf存储桶捕获所有观察结果,因此其计数是观察结果的总数。

总结
摘要类似于直方图,但它不使用预定义的存储桶,而是计算分位数来汇总观察到的数据。因此,它对于跟踪请求延迟或响应大小非常有用。此外,它还可以帮助我们确定关键指标,例如中位数(第 50 百分位数)或第 90 百分位数:

Summary requestDuration = Summary.builder()
  .name("http_request_duration_seconds")
  .help(
"Tracks the duration of HTTP requests in seconds")
  .quantile(0.5, 0.05)
  .quantile(0.9, 0.01)
  .register();
for (int i = 0; i < 100; i++) {
    double duration = 0.05 + (2 * random.nextDouble());
    requestDuration.observe(duration);
}

我们定义两个分位数:

0.5(第 50 个百分位数)近似于中位数,误差为 5%。
0.9(第 90 个百分位数)表示 90% 的请求比该值更快,误差为 1%。

当 Prometheus 抓取指标时,我们将看到如下输出:

http_request_duration_seconds{quantile="0.5"} 1.3017345289221114
http_request_duration_seconds{quantile=
"0.9"} 1.8304437814581778
http_request_duration_seconds_count 100
http_request_duration_seconds_sum 110.5670284649691

分位数显示第 50 和第 90 个百分位数的观测值。换句话说,50% 的请求花费的时间少于 1.3 秒,90% 的请求花费的时间少于 1.9 秒。

信息
信息指标存储有关应用程序的静态标签。它用于版本号、构建信息或环境详细信息。它不是性能指标,而是一种向 Prometheus 输出添加信息元数据的方法。

Info appInfo = Info.builder()
  .name("app_info")
  .help(
"Application version information")
  .labelNames(
"version", "build")
  .register();
appInfo.addLabelValues(
"1.0.0", "12345");

状态集
StateSet指标表示多个状态,可以是 active 或 inactive。当我们需要跟踪应用程序的不同运行状态或功能标志状态时,它很有用:

StateSet stateSet = StateSet.builder()
  .name("feature_flags")
  .help(
"Feature flags")
  .labelNames(
"env")
  .states(
"feature1")
  .register();
stateSet.labelValues(
"dev").setFalse("feature1");


Prometheus 指标类型概述
Prometheus Java 客户端提供了各种指标来捕获应用程序性能和行为的不同维度。下面是一个汇总表,概述了每种指标类型的主要功能,包括其用途和使用示例:

度量类型    描述    示例用例
Counter    随时间推移而增加的指标,通常用于计数事件    计算 HTTP 请求或错误的数量
Gauge    它可以增加或减少,用于随时间波动的值    跟踪内存使用情况或活动线程数
直方图    测量值在可配置存储桶中的分布情况    观察请求延迟或响应大小
概括    跟踪观测值的分布并计算可配置的分位数    测量请求持续时间或延迟百分位数
信息    存储有关应用程序的元数据的静态标签    捕获版本或构建信息
状态集    跟踪多种运行状态,可以是活跃的,也可以是非活跃的    监控功能标志状态