JAVA 集成 Prometheus 抓取不到指标?/actuator/prometheus 配置问题详解

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.propertiesapplication.yml 文件中启用它:

management.endpoints.web.exposure.include=prometheus

或者,使用 YAML 格式:

management:
  endpoints:
    web:
      exposure:
        include: prometheus

以上配置会将 /actuator/prometheus 端点暴露出来。访问该端点,可以看到 Prometheus 可以识别的指标数据。

三、Prometheus 无法抓取指标的常见原因及解决方案

如果按照以上步骤配置后,Prometheus 仍然无法抓取到指标,或者抓取到的指标不符合预期,那么可能是以下原因导致的:

  1. 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
  2. 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 地址和端口号正确
  3. 防火墙或网络问题:

    • 原因: 防火墙阻止了 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
  4. 指标数据格式不正确:

    • 原因: 虽然 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);
      }
  5. 指标名称冲突:

    • 原因: 如果多个应用使用了相同的指标名称,可能会导致 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);
      }
  6. 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>
  7. Spring Boot 版本过低:

    • 原因: 如果 Spring Boot 版本过低,可能不支持 Prometheus 集成。
    • 解决方案: 建议升级到较新的 Spring Boot 版本。Spring Boot 2.x 及以上版本都支持 Prometheus 集成。
  8. 自定义指标配置错误:

    • 原因: 如果自定义了 MeterRegistryPrometheusMeterRegistry 的配置,可能会导致指标无法正确暴露。
    • 解决方案: 检查自定义的配置是否正确。例如,是否正确配置了 ClockStepRegistryConfig 等。
    • 代码示例:

      @Configuration
      public class MetricsConfig {
      
          @Bean
          public PrometheusMeterRegistry prometheusMeterRegistry(PrometheusConfig prometheusConfig, Clock clock) {
              return new PrometheusMeterRegistry(prometheusConfig, clock);
          }
      }
  9. JVM 安全管理器限制:

    • 原因: 如果启用了 JVM 安全管理器,可能会限制 Actuator 访问指标数据。
    • 解决方案: 检查 JVM 安全管理器的配置,确保允许 Actuator 访问指标数据。

四、排查步骤与调试技巧

在遇到 Prometheus 无法抓取指标的问题时,可以按照以下步骤进行排查:

  1. 检查 Actuator 端点是否启用和暴露: 访问 /actuator/health/actuator/prometheus 端点,确认是否可以正常访问。
  2. 检查 Prometheus 配置: 检查 prometheus.yml 文件,确认 scrape_configs 配置是否正确。
  3. 检查网络连接: 使用 telnetcurl 命令测试 Prometheus 是否可以访问目标服务的 /actuator/prometheus 端点。
  4. 检查指标数据格式: 访问 /actuator/prometheus 端点,查看指标数据是否符合 Prometheus 的格式要求。
  5. 检查日志: 查看 Spring Boot 应用的日志和 Prometheus 的日志,寻找错误信息。
  6. 使用调试器: 可以使用调试器来调试 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 抓取不到指标的原因,并提供了详尽的解决方案和代码示例。希望大家能够回顾重点,融会贯通,并在实际工作中持续学习,不断提升自己的技能。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注