JAVA 集成 Prometheus 抓取不到指标?/actuator/prometheus 配置问题详解
各位朋友,大家好!今天我们来深入探讨一个在微服务架构中非常常见的,但又容易让人头疼的问题:JAVA 应用集成了 Prometheus,但是 Prometheus 却无法抓取到指标,或者抓取到的指标不符合预期。特别是当使用 Spring Boot Actuator 的 /actuator/prometheus 端点时,问题可能会更加复杂。
我们将从问题的根源出发,一步步排查可能的原因,并提供详尽的解决方案和代码示例。希望通过今天的讲解,大家能够对 Prometheus 的工作原理,以及 Spring Boot Actuator 的配置有更深入的理解,最终能够顺利解决实际工作中遇到的问题。
一、Prometheus 工作原理与指标类型
在深入讨论问题之前,我们先来回顾一下 Prometheus 的基本工作原理。Prometheus 是一个开源的监控系统,它通过定期抓取(scrape)目标服务的指标数据来收集信息。这些指标数据可以是各种各样的,例如 CPU 使用率、内存占用、请求延迟、错误率等等。
Prometheus 支持多种指标类型,理解这些类型对于正确配置和使用 Prometheus 至关重要。常见的指标类型包括:
-
Counter (计数器): 用于表示单调递增的数值,例如请求总数、错误总数。Counter 只能增加,不能减少。如果 Counter 重置,Prometheus 会认为服务重启。
-
Gauge (仪表盘): 用于表示可以任意变化的数值,例如 CPU 使用率、内存占用、温度。Gauge 可以增加和减少。
-
Histogram (直方图): 用于统计数据的分布情况,例如请求延迟的分布。Histogram 会将数据划分到不同的桶(bucket)中,并统计每个桶中的数据量。
-
Summary (摘要): 类似于 Histogram,但 Summary 不会预先定义桶,而是直接计算分位数(quantile),例如 90% 分位数、99% 分位数。
了解不同指标类型的特点,有助于我们选择合适的指标类型来监控不同的业务场景。
二、Spring Boot Actuator 与 Prometheus 集成
Spring Boot Actuator 提供了一系列用于监控和管理 Spring Boot 应用的端点。其中,/actuator/prometheus 端点可以将应用的指标数据以 Prometheus 可以识别的格式暴露出来。
要启用 /actuator/prometheus 端点,需要在 pom.xml 文件中添加以下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
<scope>runtime</scope>
</dependency>
添加依赖后,默认情况下 /actuator/prometheus 端点是禁用的。需要在 application.properties 或 application.yml 文件中启用它:
management.endpoints.web.exposure.include=prometheus
或者,使用 YAML 格式:
management:
endpoints:
web:
exposure:
include: prometheus
以上配置会将 /actuator/prometheus 端点暴露出来。访问该端点,可以看到 Prometheus 可以识别的指标数据。
三、Prometheus 无法抓取指标的常见原因及解决方案
如果按照以上步骤配置后,Prometheus 仍然无法抓取到指标,或者抓取到的指标不符合预期,那么可能是以下原因导致的:
-
Actuator 端点未启用或未暴露:
- 原因: 最常见的原因是 Actuator 端点没有被正确启用或暴露。
- 解决方案: 确保
management.endpoints.web.exposure.include配置项包含了prometheus,并且 Actuator 的基础端点已经启用(management.endpoints.enabled默认是true)。检查配置文件是否生效,可以使用 Spring Boot Actuator 的/actuator/health端点来验证 Actuator 是否正常工作。如果/actuator/health端点也无法访问,那么可能是 Actuator 的基础配置有问题。 -
代码示例:
# 正确的配置 management.endpoints.web.exposure.include=prometheus,health,info # 错误的配置 (prometheus 未包含在 include 中) management.endpoints.web.exposure.include=health,info # 错误的配置 (endpoints 被禁用) management.endpoints.enabled=false
-
Prometheus 配置错误:
- 原因: Prometheus 的配置文件
prometheus.yml中的scrape_configs配置不正确,导致 Prometheus 无法找到目标服务。 - 解决方案: 检查
prometheus.yml文件,确保scrape_configs中配置了正确的targets,并且targets指向的 IP 地址和端口号是正确的。同时,也要确保scrape_interval配置合理,不要设置得太长,否则 Prometheus 无法及时抓取指标。 -
代码示例:
scrape_configs: - job_name: 'my-java-app' scrape_interval: 5s static_configs: - targets: ['192.168.1.100:8080'] # 确保 IP 地址和端口号正确
- 原因: Prometheus 的配置文件
-
防火墙或网络问题:
- 原因: 防火墙阻止了 Prometheus 访问目标服务的
/actuator/prometheus端点。或者,Prometheus 和目标服务不在同一个网络中,导致无法互相访问。 - 解决方案: 检查防火墙规则,确保 Prometheus 可以访问目标服务的端口。如果 Prometheus 和目标服务不在同一个网络中,需要配置网络路由或 VPN,确保它们可以互相访问。可以使用
telnet命令或curl命令来测试 Prometheus 是否可以访问目标服务的/actuator/prometheus端点。 -
代码示例:
# 使用 telnet 命令测试连接 telnet 192.168.1.100 8080 # 使用 curl 命令测试访问 /actuator/prometheus 端点 curl http://192.168.1.100:8080/actuator/prometheus
- 原因: 防火墙阻止了 Prometheus 访问目标服务的
-
指标数据格式不正确:
- 原因: 虽然 Spring Boot Actuator 默认会生成 Prometheus 可以识别的指标数据格式,但在某些情况下,如果自定义了指标,可能会导致指标数据格式不正确。
- 解决方案: 确保自定义的指标数据符合 Prometheus 的格式要求。 Prometheus 的格式要求比较严格,指标名称、标签名称、指标类型等都需要符合规范。可以使用 Prometheus 的查询语言 PromQL 来验证指标数据是否正确。
-
代码示例:
// 使用 MeterRegistry 自定义指标 @Autowired private MeterRegistry meterRegistry; public void recordRequest(String endpoint, long duration) { meterRegistry.timer("my_app_request_duration", "endpoint", endpoint).record(duration, TimeUnit.MILLISECONDS); }
-
指标名称冲突:
- 原因: 如果多个应用使用了相同的指标名称,可能会导致 Prometheus 无法区分不同的应用,从而导致抓取到的指标数据不正确。
- 解决方案: 确保不同的应用使用不同的指标名称。可以使用应用名称或环境名称作为指标名称的前缀,以区分不同的应用。
-
代码示例:
// 使用应用名称作为指标名称的前缀 @Value("${spring.application.name}") private String applicationName; @Autowired private MeterRegistry meterRegistry; public void recordRequest(String endpoint, long duration) { meterRegistry.timer(applicationName + "_request_duration", "endpoint", endpoint).record(duration, TimeUnit.MILLISECONDS); }
-
Micrometer 版本冲突:
- 原因: 如果项目中使用了多个版本的 Micrometer 依赖,可能会导致版本冲突,从而导致指标数据无法正确暴露。
- 解决方案: 确保项目中只使用一个版本的 Micrometer 依赖。可以使用 Maven 的 dependency management 功能来统一管理 Micrometer 的版本。
-
代码示例:
<dependencyManagement> <dependencies> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-bom</artifactId> <version>1.10.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
-
Spring Boot 版本过低:
- 原因: 如果 Spring Boot 版本过低,可能不支持 Prometheus 集成。
- 解决方案: 建议升级到较新的 Spring Boot 版本。Spring Boot 2.x 及以上版本都支持 Prometheus 集成。
-
自定义指标配置错误:
- 原因: 如果自定义了
MeterRegistry或PrometheusMeterRegistry的配置,可能会导致指标无法正确暴露。 - 解决方案: 检查自定义的配置是否正确。例如,是否正确配置了
Clock、StepRegistryConfig等。 -
代码示例:
@Configuration public class MetricsConfig { @Bean public PrometheusMeterRegistry prometheusMeterRegistry(PrometheusConfig prometheusConfig, Clock clock) { return new PrometheusMeterRegistry(prometheusConfig, clock); } }
- 原因: 如果自定义了
-
JVM 安全管理器限制:
- 原因: 如果启用了 JVM 安全管理器,可能会限制 Actuator 访问指标数据。
- 解决方案: 检查 JVM 安全管理器的配置,确保允许 Actuator 访问指标数据。
四、排查步骤与调试技巧
在遇到 Prometheus 无法抓取指标的问题时,可以按照以下步骤进行排查:
- 检查 Actuator 端点是否启用和暴露: 访问
/actuator/health和/actuator/prometheus端点,确认是否可以正常访问。 - 检查 Prometheus 配置: 检查
prometheus.yml文件,确认scrape_configs配置是否正确。 - 检查网络连接: 使用
telnet或curl命令测试 Prometheus 是否可以访问目标服务的/actuator/prometheus端点。 - 检查指标数据格式: 访问
/actuator/prometheus端点,查看指标数据是否符合 Prometheus 的格式要求。 - 检查日志: 查看 Spring Boot 应用的日志和 Prometheus 的日志,寻找错误信息。
- 使用调试器: 可以使用调试器来调试 Spring Boot 应用,查看指标数据的生成过程。
五、高级配置与优化
除了基本的配置外,还可以进行一些高级配置和优化,以提高 Prometheus 的性能和可靠性:
-
使用 Service Discovery: 可以使用 Prometheus 的 Service Discovery 功能来自动发现目标服务。例如,可以使用 Kubernetes Service Discovery、Consul Service Discovery 等。
-
配置 Relabeling: 可以使用 Prometheus 的 Relabeling 功能来修改指标的标签。例如,可以添加应用名称标签、环境名称标签等。
-
配置 Alerting: 可以使用 Prometheus 的 Alerting 功能来配置告警规则。例如,可以配置 CPU 使用率超过 80% 时发送告警。
-
使用 Remote Write: 可以使用 Prometheus 的 Remote Write 功能将指标数据写入到其他的存储系统中。例如,可以写入到 Thanos、Cortex 等。
六、代码示例:自定义指标并暴露
以下代码示例展示了如何自定义指标并暴露给 Prometheus:
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class CustomMetricsService {
private final Counter myCustomCounter;
@Autowired
public CustomMetricsService(MeterRegistry meterRegistry) {
this.myCustomCounter = Counter.builder("my_custom_counter")
.description("A custom counter for demonstration purposes")
.tag("environment", "production")
.register(meterRegistry);
}
public void incrementCounter() {
myCustomCounter.increment();
}
}
在 Controller 中使用:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyController {
@Autowired
private CustomMetricsService customMetricsService;
@GetMapping("/increment")
public String increment() {
customMetricsService.incrementCounter();
return "Counter incremented!";
}
}
访问 /increment 接口后,my_custom_counter 指标的值就会增加。可以在 /actuator/prometheus 端点看到这个指标。
七、常见问题与解答
| 问题 | 解决方案 |
|---|---|
| Prometheus 抓取不到任何指标 | 1. 检查 Actuator 端点是否启用和暴露 (management.endpoints.web.exposure.include=prometheus); 2. 检查 Prometheus 配置 (prometheus.yml) 中的 targets 是否正确; 3. 检查网络连接是否正常,确保 Prometheus 可以访问目标服务的 /actuator/prometheus 端点。 |
| Prometheus 抓取到的指标值不正确 | 1. 检查指标类型是否选择正确; 2. 检查指标名称是否冲突; 3. 检查指标计算逻辑是否正确; 4. 如果是自定义指标,检查指标数据格式是否符合 Prometheus 的要求。 |
| Prometheus 抓取到部分指标,但缺少一些 | 1. 检查 Actuator 端点是否暴露了所有需要的指标; 2. 检查自定义的指标是否已经注册到 MeterRegistry 中; 3. 检查 Micrometer 的版本是否正确; 4. 检查是否使用了某些配置项过滤了部分指标。 |
| Prometheus 频繁重启服务导致 Counter 重置 | Counter 类型的数据只能增加不能减少,如果服务重启会导致数据重置。可以考虑使用 Gauge 类型来替代 Counter 类型,或者使用 Prometheus 的 increase() 函数来计算增长率,从而避免服务重启导致数据重置的问题。如果确实需要使用 Counter,可以考虑将数据持久化到外部存储中,并在服务启动时恢复数据。 |
明确问题、逐个排查、善用工具
希望今天的讲解能够帮助大家解决 JAVA 应用集成 Prometheus 抓取不到指标的问题。记住,遇到问题时,要明确问题的根源,逐个排查可能的原因,并善用各种调试工具。只要掌握了正确的方法,相信大家一定能够顺利解决实际工作中遇到的问题。
回顾重点,融会贯通,持续学习
我们今天深入研究了 Prometheus 的工作原理、Spring Boot Actuator 的集成,以及各种可能导致 Prometheus 抓取不到指标的原因,并提供了详尽的解决方案和代码示例。希望大家能够回顾重点,融会贯通,并在实际工作中持续学习,不断提升自己的技能。