随着分布式系统变得越来越复杂,监控对于维护应用程序性能和快速识别问题变得至关重要。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 它可以增加或减少,用于随时间波动的值 跟踪内存使用情况或活动线程数 直方图 测量值在可配置存储桶中的分布情况 观察请求延迟或响应大小 概括 跟踪观测值的分布并计算可配置的分位数 测量请求持续时间或延迟百分位数 信息 存储有关应用程序的元数据的静态标签 捕获版本或构建信息 状态集 跟踪多种运行状态,可以是活跃的,也可以是非活跃的 监控功能标志状态
|