使用 meterRegistry.timer 统计耗时

meterRegistry.timer 如何 统计 平均 最小 耗时
 
在 Java 中,meterRegistry.timer 是 Micrometer 库提供的用于计时操作的工具,Micrometer 是一个应用程序指标收集的外观模式库,支持多种监控系统。下面详细介绍如何使用 meterRegistry.timer 来统计平均耗时和最小耗时。

1. 添加依赖

首先,你需要在项目中添加 Micrometer 的依赖。如果你使用的是 Maven,可以在 pom.xml 中添加以下依赖:

xml
 
 
 
 
 
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-core</artifactId>
    <version>1.11.4</version>
</dependency>
 

2. 编写示例代码

以下是一个完整的示例代码,展示了如何使用 meterRegistry.timer 来统计平均耗时和最小耗时:

java
 
 
 
 
 
import io.micrometer.core.instrument.Clock;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;

import java.util.concurrent.TimeUnit;

public class TimerStatisticsExample {
    public static void main(String[] args) {
        // 创建一个简单的 MeterRegistry 实例
        MeterRegistry meterRegistry = new SimpleMeterRegistry(Clock.SYSTEM);

        // 创建一个计时器
        Timer timer = meterRegistry.timer("my.timer");

        // 模拟多次操作
        for (int i = 0; i < 10; i++) {
            // 开始计时
            Timer.Sample sample = Timer.start(meterRegistry);
            try {
                // 模拟一些耗时操作
                Thread.sleep((long) (Math.random() * 100));
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            // 结束计时并记录结果
            sample.stop(timer);
        }

        // 获取平均耗时
        double meanTime = timer.mean(TimeUnit.MILLISECONDS);
        System.out.println("平均耗时: " + meanTime + " 毫秒");

        // 获取最小耗时
        double minTime = timer.min(TimeUnit.MILLISECONDS);
        System.out.println("最小耗时: " + minTime + " 毫秒");
    }
}
 

3. 代码解释

  • 创建 MeterRegistry 实例SimpleMeterRegistry 是 Micrometer 提供的一个简单的注册表实现,用于存储和管理所有的指标。
  • 创建计时器:使用 meterRegistry.timer 方法创建一个名为 "my.timer" 的计时器。
  • 模拟耗时操作:使用 Timer.Sample 类来记录每次操作的开始时间,操作完成后调用 sample.stop(timer) 方法来结束计时并将结果记录到计时器中。
  • 获取统计信息
    • timer.mean(TimeUnit.MILLISECONDS) 方法用于获取平均耗时,单位为毫秒。
    • timer.min(TimeUnit.MILLISECONDS) 方法用于获取最小耗时,单位为毫秒。

4. 注意事项

  • timer.min() 方法在某些情况下可能返回 0,这是因为 Micrometer 的计时器实现可能不会精确记录最小耗时。如果需要更精确的最小耗时统计,你可以手动维护一个最小耗时变量。
  • 不同的 MeterRegistry 实现可能会有不同的统计精度和性能,你可以根据实际需求选择合适的实现。
 
 
spring boot 如何 结合 Prometheus 和 Grafana,按照 get请求的入参orgCode 和 prodCode 两个维度 ,统计http的 成功请求数量,失败请求数量,最小耗时,最大耗时,平均耗时,95%耗时,99%耗时,标准差,qps,总请求占比 等指标。
 
要在 Spring Boot 中结合 Prometheus 和 Grafana,按照 orgCode 和 prodCode 两个维度统计 HTTP 请求的各项指标,可以按照以下步骤进行:

1. 添加依赖

在 pom.xml 中添加必要的依赖:

xml
 
 
 
 
 
<dependencies>
    <!-- Spring Boot Actuator -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <!-- Micrometer Prometheus Registry -->
    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-registry-prometheus</artifactId>
    </dependency>
    <!-- Spring Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>
 

2. 配置 Spring Boot

在 application.properties 或 application.yml 中添加以下配置:

properties
 
 
 
 
 
# 开启 Actuator 的 Prometheus 端点
management.endpoints.web.exposure.include=prometheus
# 启用 Micrometer 的 HTTP 请求统计
management.metrics.web.server.request.autotime.enabled=true
 

3. 自定义拦截器来记录 orgCode 和 prodCode

创建一个拦截器来记录请求的 orgCode 和 prodCode,并将其作为标签添加到指标中:

java
 
 
 
 
 
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

@Component
public class RequestTaggingInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String orgCode = request.getParameter("orgCode");
        String prodCode = request.getParameter("prodCode");

        Tags tags = Tags.of(
                Tag.of("orgCode", orgCode != null ? orgCode : "unknown"),
                Tag.of("prodCode", prodCode != null ? prodCode : "unknown")
        );

        request.setAttribute("requestTags", tags);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 可以在这里做一些后置处理
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 可以在这里做一些完成后的处理
    }
}
 

4. 配置拦截器

创建一个配置类来注册拦截器:

java
 
 
 
 
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private RequestTaggingInterceptor requestTaggingInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(requestTaggingInterceptor);
    }
}
 

5. 自定义 MeterFilter 来添加标签

创建一个 MeterFilter 来将 orgCode 和 prodCode 标签添加到 HTTP 请求指标中:

java
 
 
 
 
 
import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.config.MeterFilter;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.Optional;

@Component
public class RequestTaggingMeterFilter implements MeterFilter {

    @Override
    public Meter.Id map(Meter.Id id) {
        if (id.getName().startsWith("http.server.requests")) {
            HttpServletRequest request = getCurrentRequest();
            if (request != null) {
                Optional.ofNullable(request.getAttribute("requestTags"))
                        .ifPresent(tags -> id = id.withTags((Iterable<io.micrometer.core.instrument.Tag>) tags));
            }
        }
        return id;
    }

    private HttpServletRequest getCurrentRequest() {
        // 这里需要根据实际情况获取当前请求对象
        // 可以使用 RequestContextHolder 等方式
        return null;
    }
}
 

6. 启动 Prometheus 和 Grafana

  • Prometheus:下载并启动 Prometheus,配置 prometheus.yml 文件来收集 Spring Boot 应用的指标:

yaml
 
 
 
 
 
global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'spring-boot-app'
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets: ['localhost:8080']
 

  • Grafana:下载并启动 Grafana,添加 Prometheus 作为数据源。

7. 在 Grafana 中创建仪表盘

在 Grafana 中创建一个新的仪表盘,并添加以下查询来统计各项指标:

  • 成功请求数量

promql
 
 
 
 
 
sum(rate(http_server_requests_seconds_count{status=~"2..", orgCode!="unknown", prodCode!="unknown"}[5m])) by (orgCode, prodCode)
 

  • 失败请求数量

promql
 
 
 
 
 
sum(rate(http_server_requests_seconds_count{status=~"[45]..", orgCode!="unknown", prodCode!="unknown"}[5m])) by (orgCode, prodCode)
 

  • 最小耗时

promql
 
 
 
 
 
min(http_server_requests_seconds_bucket{le="+Inf", orgCode!="unknown", prodCode!="unknown"}) by (orgCode, prodCode)
 

  • 最大耗时

promql
 
 
 
 
 
max(http_server_requests_seconds_bucket{le="+Inf", orgCode!="unknown", prodCode!="unknown"}) by (orgCode, prodCode)
 

  • 平均耗时

promql
 
 
 
 
 
sum(rate(http_server_requests_seconds_sum{orgCode!="unknown", prodCode!="unknown"}[5m])) by (orgCode, prodCode)
/
sum(rate(http_server_requests_seconds_count{orgCode!="unknown", prodCode!="unknown"}[5m])) by (orgCode, prodCode)
 

  • 95% 耗时

promql
 
 
 
 
 
histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{orgCode!="unknown", prodCode!="unknown"}[5m])) by (le, orgCode, prodCode))
 

  • 99% 耗时

promql
 
 
 
 
 
histogram_quantile(0.99, sum(rate(http_server_requests_seconds_bucket{orgCode!="unknown", prodCode!="unknown"}[5m])) by (le, orgCode, prodCode))
 

  • 标准差

promql
 
 
 
 
 
sqrt(
  (sum(rate(http_server_requests_seconds_sum_of_squares{orgCode!="unknown", prodCode!="unknown"}[5m])) by (orgCode, prodCode)
  / sum(rate(http_server_requests_seconds_count{orgCode!="unknown", prodCode!="unknown"}[5m])) by (orgCode, prodCode))
  -
  (sum(rate(http_server_requests_seconds_sum{orgCode!="unknown", prodCode!="unknown"}[5m])) by (orgCode, prodCode)
  / sum(rate(http_server_requests_seconds_count{orgCode!="unknown", prodCode!="unknown"}[5m])) by (orgCode, prodCode)) ^ 2
)
 

  • QPS

promql
 
 
 
 
 
sum(rate(http_server_requests_seconds_count{orgCode!="unknown", prodCode!="unknown"}[5m])) by (orgCode, prodCode)
 

  • 总请求占比

promql
 
 
 
 
 
sum(rate(http_server_requests_seconds_count{orgCode!="unknown", prodCode!="unknown"}[5m])) by (orgCode, prodCode)
/
sum(rate(http_server_requests_seconds_count[5m]))
 

通过以上步骤,你就可以在 Spring Boot 中结合 Prometheus 和 Grafana,按照 orgCode 和 prodCode 两个维度统计 HTTP 请求的各项指标。
 
 
如果不用 filter实现 而是通过 Controller层 手动插入代码的方式呢?
 
如果不使用过滤器(Filter),而是在 Controller 层手动插入代码来实现按照 orgCode 和 prodCode 两个维度统计 HTTP 请求的各项指标,可以参考以下步骤和示例代码:

1. 添加依赖

确保 pom.xml 中包含必要的依赖,这些依赖和之前使用过滤器时的依赖一致:

xml
 
 
 
 
 
<dependencies>
    <!-- Spring Boot Actuator -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <!-- Micrometer Prometheus Registry -->
    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-registry-prometheus</artifactId>
    </dependency>
    <!-- Spring Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>
 

2. 配置 Spring Boot

在 application.properties 或 application.yml 中添加以下配置:

properties
 
 
 
 
 
# 开启 Actuator 的 Prometheus 端点
management.endpoints.web.exposure.include=prometheus
# 启用 Micrometer 的 HTTP 请求统计
management.metrics.web.server.request.autotime.enabled=true
 

3. 创建 Controller 并手动统计指标

java
 
 
 
 
 
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@RestController
public class MyController {

    private final MeterRegistry meterRegistry;

    @Autowired
    public MyController(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
    }

    @GetMapping("/myEndpoint")
    public String myEndpoint(@RequestParam(required = false) String orgCode, @RequestParam(required = false) String prodCode) {
        orgCode = orgCode != null ? orgCode : "unknown";
        prodCode = prodCode != null ? prodCode : "unknown";

        // 开始计时
        Timer.Sample sample = Timer.start(meterRegistry);

        try {
            // 模拟一些业务逻辑
            Thread.sleep((long) (Math.random() * 100));

            // 成功请求计数器
            Counter successCounter = meterRegistry.counter("http_requests_success", "orgCode", orgCode, "prodCode", prodCode);
            successCounter.increment();

            return "Success";
        } catch (Exception e) {
            // 失败请求计数器
            Counter failureCounter = meterRegistry.counter("http_requests_failure", "orgCode", orgCode, "prodCode", prodCode);
            failureCounter.increment();
            return "Failure";
        } finally {
            // 结束计时并记录结果
            Timer timer = meterRegistry.timer("http_requests_timer", "orgCode", orgCode, "prodCode", prodCode);
            sample.stop(timer);
        }
    }
}
 

代码解释

  • 注入 MeterRegistry:通过构造函数注入 MeterRegistry,它是 Micrometer 用于管理和记录指标的核心组件。
  • 获取请求参数:从请求中获取 orgCode 和 prodCode,如果参数为空则设置为 "unknown"
  • 开始计时:使用 Timer.Sample 开始计时,记录请求处理的开始时间。
  • 业务逻辑处理:模拟一些业务逻辑,这里使用 Thread.sleep 模拟耗时操作。
  • 统计成功和失败请求数量
    • 如果业务逻辑执行成功,使用 Counter 增加成功请求的计数。
    • 如果业务逻辑抛出异常,使用另一个 Counter 增加失败请求的计数。
  • 结束计时:在 finally 块中结束计时,并将结果记录到 Timer 中。

4. 启动 Prometheus 和 Grafana

这部分和使用过滤器时的步骤相同,需要下载并启动 Prometheus 和 Grafana,配置 Prometheus 来收集 Spring Boot 应用的指标,并在 Grafana 中添加 Prometheus 作为数据源。

5. 在 Grafana 中创建仪表盘

在 Grafana 中创建一个新的仪表盘,并添加以下查询来统计各项指标:

  • 成功请求数量

promql
 
 
 
 
 
sum(rate(http_requests_success_total[5m])) by (orgCode, prodCode)
 

  • 失败请求数量

promql
 
 
 
 
 
sum(rate(http_requests_failure_total[5m])) by (orgCode, prodCode)
 

  • 最小耗时

promql
 
 
 
 
 
min(http_requests_timer_seconds_bucket{le="+Inf"}) by (orgCode, prodCode)
 

  • 最大耗时

promql
 
 
 
 
 
max(http_requests_timer_seconds_bucket{le="+Inf"}) by (orgCode, prodCode)
 

  • 平均耗时

promql
 
 
 
 
 
sum(rate(http_requests_timer_seconds_sum[5m])) by (orgCode, prodCode)
/
sum(rate(http_requests_timer_seconds_count[5m])) by (orgCode, prodCode)
 

  • 95% 耗时

promql
 
 
 
 
 
histogram_quantile(0.95, sum(rate(http_requests_timer_seconds_bucket[5m])) by (le, orgCode, prodCode))
 

  • 99% 耗时

promql
 
 
 
 
 
histogram_quantile(0.99, sum(rate(http_requests_timer_seconds_bucket[5m])) by (le, orgCode, prodCode))
 

  • 标准差

promql
 
 
 
 
 
sqrt(
  (sum(rate(http_requests_timer_seconds_sum_of_squares[5m])) by (orgCode, prodCode)
  / sum(rate(http_requests_timer_seconds_count[5m])) by (orgCode, prodCode))
  -
  (sum(rate(http_requests_timer_seconds_sum[5m])) by (orgCode, prodCode)
  / sum(rate(http_requests_timer_seconds_count[5m])) by (orgCode, prodCode)) ^ 2
)
 

  • QPS

promql
 
 
 
 
 
sum(rate(http_requests_timer_seconds_count[5m])) by (orgCode, prodCode)
 

  • 总请求占比

promql
 
 
 
 
 
sum(rate(http_requests_timer_seconds_count[5m])) by (orgCode, prodCode)
/
sum(rate(http_requests_timer_seconds_count[5m]))
 

通过以上步骤,你可以在 Controller 层手动插入代码来实现按照 orgCode 和 prodCode 两个维度统计 HTTP 请求的各项指标。这种方式更加灵活,但需要在每个需要统计的 Controller 方法中手动添加统计代码。
 
 
统一在 http_requests_ 标签前 添加 ent_credit_api_query_
 
如果你想统一在 http_requests_ 标签前添加 ent_credit_api_query_,可以按照以下步骤进行修改:

1. 修改 Controller 代码

java
 
 
 
 
 
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@RestController
public class MyController {

    private final MeterRegistry meterRegistry;

    @Autowired
    public MyController(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
    }

    @GetMapping("/myEndpoint")
    public String myEndpoint(@RequestParam(required = false) String orgCode, @RequestParam(required = false) String prodCode) {
        orgCode = orgCode != null ? orgCode : "unknown";
        prodCode = prodCode != null ? prodCode : "unknown";

        // 开始计时
        Timer.Sample sample = Timer.start(meterRegistry);

        try {
            // 模拟一些业务逻辑
            Thread.sleep((long) (Math.random() * 100));

            // 成功请求计数器
            Counter successCounter = meterRegistry.counter("ent_credit_api_query_http_requests_success", "orgCode", orgCode, "prodCode", prodCode);
            successCounter.increment();

            return "Success";
        } catch (Exception e) {
            // 失败请求计数器
            Counter failureCounter = meterRegistry.counter("ent_credit_api_query_http_requests_failure", "orgCode", orgCode, "prodCode", prodCode);
            failureCounter.increment();
            return "Failure";
        } finally {
            // 结束计时并记录结果
            Timer timer = meterRegistry.timer("ent_credit_api_query_http_requests_timer", "orgCode", orgCode, "prodCode", prodCode);
            sample.stop(timer);
        }
    }
}
 

2. 修改 Grafana 查询语句

  • 成功请求数量

promql
 
 
 
 
 
sum(rate(ent_credit_api_query_http_requests_success_total[5m])) by (orgCode, prodCode)
 

  • 失败请求数量

promql
 
 
 
 
 
sum(rate(ent_credit_api_query_http_requests_failure_total[5m])) by (orgCode, prodCode)
 

  • 最小耗时

promql
 
 
 
 
 
min(ent_credit_api_query_http_requests_timer_seconds_bucket{le="+Inf"}) by (orgCode, prodCode)
 

  • 最大耗时

promql
 
 
 
 
 
max(ent_credit_api_query_http_requests_timer_seconds_bucket{le="+Inf"}) by (orgCode, prodCode)
 

  • 平均耗时

promql
 
 
 
 
 
sum(rate(ent_credit_api_query_http_requests_timer_seconds_sum[5m])) by (orgCode, prodCode)
/
sum(rate(ent_credit_api_query_http_requests_timer_seconds_count[5m])) by (orgCode, prodCode)
 

  • 95% 耗时

promql
 
 
 
 
 
histogram_quantile(0.95, sum(rate(ent_credit_api_query_http_requests_timer_seconds_bucket[5m])) by (le, orgCode, prodCode))
 

  • 99% 耗时

promql
 
 
 
 
 
histogram_quantile(0.99, sum(rate(ent_credit_api_query_http_requests_timer_seconds_bucket[5m])) by (le, orgCode, prodCode))
 

  • 标准差

promql
 
 
 
 
 
sqrt(
  (sum(rate(ent_credit_api_query_http_requests_timer_seconds_sum_of_squares[5m])) by (orgCode, prodCode)
  / sum(rate(ent_credit_api_query_http_requests_timer_seconds_count[5m])) by (orgCode, prodCode))
  -
  (sum(rate(ent_credit_api_query_http_requests_timer_seconds_sum[5m])) by (orgCode, prodCode)
  / sum(rate(ent_credit_api_query_http_requests_timer_seconds_count[5m])) by (orgCode, prodCode)) ^ 2
)
 

  • QPS

promql
 
 
 
 
 
sum(rate(ent_credit_api_query_http_requests_timer_seconds_count[5m])) by (orgCode, prodCode)
 

  • 总请求占比

promql
 
 
 
 
 
sum(rate(ent_credit_api_query_http_requests_timer_seconds_count[5m])) by (orgCode, prodCode)
/
sum(rate(ent_credit_api_query_http_requests_timer_seconds_count[5m]))
 

通过上述修改,就可以统一在 http_requests_ 标签前添加 ent_credit_api_query_,确保指标名称的一致性和可识别性。同时,在 Grafana 中使用修改后的指标名称进行查询,以获取正确的统计数据。
 
 
修改 Grafana 查询语句 分别按照orgCode和prodCode 两个维度 统计 当天内的 成功请求数量,失败请求数量,最小耗时,最大耗时,平均耗时,95% 耗时,99% 耗时,标准差,QPS,总请求占比
 
以下是分别按照 orgCode 和 prodCode 两个维度,统计当天内各项指标的 Grafana 查询语句,假设你的指标名称已经按照前面所说统一为 ent_credit_api_query_http_requests_ 开头。

1. 按照 orgCode 维度统计

成功请求数量

promql
 
 
 
 
 
sum(increase(ent_credit_api_query_http_requests_success_total{job="your_job_name"}[1d])) by (orgCode)
 

这里的 your_job_name 需要替换为你 Prometheus 配置中定义的实际作业名称。increase 函数用于计算在指定时间范围内(这里是 1 天)指标的增量,sum 函数将结果按 orgCode 分组求和。

失败请求数量

promql
 
 
 
 
 
sum(increase(ent_credit_api_query_http_requests_failure_total{job="your_job_name"}[1d])) by (orgCode)
 

最小耗时

promql
 
 
 
 
 
min(ent_credit_api_query_http_requests_timer_seconds_bucket{job="your_job_name", le="+Inf", __name__=~".*_bucket"}[1d]) by (orgCode)
 

最大耗时

promql
 
 
 
 
 
max(ent_credit_api_query_http_requests_timer_seconds_bucket{job="your_job_name", le="+Inf", __name__=~".*_bucket"}[1d]) by (orgCode)
 

平均耗时

promql
 
 
 
 
 
sum(increase(ent_credit_api_query_http_requests_timer_seconds_sum{job="your_job_name"}[1d])) by (orgCode)
/
sum(increase(ent_credit_api_query_http_requests_timer_seconds_count{job="your_job_name"}[1d])) by (orgCode)
 

95% 耗时

promql
 
 
 
 
 
histogram_quantile(0.95, sum(increase(ent_credit_api_query_http_requests_timer_seconds_bucket{job="your_job_name"}[1d])) by (le, orgCode))
 

99% 耗时

promql
 
 
 
 
 
histogram_quantile(0.99, sum(increase(ent_credit_api_query_http_requests_timer_seconds_bucket{job="your_job_name"}[1d])) by (le, orgCode))
 

标准差

promql
 
 
 
 
 
sqrt(
  (sum(increase(ent_credit_api_query_http_requests_timer_seconds_sum_of_squares{job="your_job_name"}[1d])) by (orgCode)
  / sum(increase(ent_credit_api_query_http_requests_timer_seconds_count{job="your_job_name"}[1d])) by (orgCode))
  -
  (sum(increase(ent_credit_api_query_http_requests_timer_seconds_sum{job="your_job_name"}[1d])) by (orgCode)
  / sum(increase(ent_credit_api_query_http_requests_timer_seconds_count{job="your_job_name"}[1d])) by (orgCode)) ^ 2
)
 

QPS(每秒查询率)

promql
 
 
 
 
 
sum(increase(ent_credit_api_query_http_requests_timer_seconds_count{job="your_job_name"}[1d])) by (orgCode)
/
86400
 

这里 86400 是一天的秒数。

总请求占比

promql
 
 
 
 
 
sum(increase(ent_credit_api_query_http_requests_timer_seconds_count{job="your_job_name"}[1d])) by (orgCode)
/
sum(increase(ent_credit_api_query_http_requests_timer_seconds_count{job="your_job_name"}[1d]))
 

2. 按照 prodCode 维度统计

成功请求数量

promql
 
 
 
 
 
sum(increase(ent_credit_api_query_http_requests_success_total{job="your_job_name"}[1d])) by (prodCode)
 

失败请求数量

promql
 
 
 
 
 
sum(increase(ent_credit_api_query_http_requests_failure_total{job="your_job_name"}[1d])) by (prodCode)
 

最小耗时

promql
 
 
 
 
 
min(ent_credit_api_query_http_requests_timer_seconds_bucket{job="your_job_name", le="+Inf", __name__=~".*_bucket"}[1d]) by (prodCode)
 

最大耗时

promql
 
 
 
 
 
max(ent_credit_api_query_http_requests_timer_seconds_bucket{job="your_job_name", le="+Inf", __name__=~".*_bucket"}[1d]) by (prodCode)
 

平均耗时

promql
 
 
 
 
 
sum(increase(ent_credit_api_query_http_requests_timer_seconds_sum{job="your_job_name"}[1d])) by (prodCode)
/
sum(increase(ent_credit_api_query_http_requests_timer_seconds_count{job="your_job_name"}[1d])) by (prodCode)
 

95% 耗时

promql
 
 
 
 
 
histogram_quantile(0.95, sum(increase(ent_credit_api_query_http_requests_timer_seconds_bucket{job="your_job_name"}[1d])) by (le, prodCode))
 

99% 耗时

promql
 
 
 
 
 
histogram_quantile(0.99, sum(increase(ent_credit_api_query_http_requests_timer_seconds_bucket{job="your_job_name"}[1d])) by (le, prodCode))
 

标准差

promql
 
 
 
 
 
sqrt(
  (sum(increase(ent_credit_api_query_http_requests_timer_seconds_sum_of_squares{job="your_job_name"}[1d])) by (prodCode)
  / sum(increase(ent_credit_api_query_http_requests_timer_seconds_count{job="your_job_name"}[1d])) by (prodCode))
  -
  (sum(increase(ent_credit_api_query_http_requests_timer_seconds_sum{job="your_job_name"}[1d])) by (prodCode)
  / sum(increase(ent_credit_api_query_http_requests_timer_seconds_count{job="your_job_name"}[1d])) by (prodCode)) ^ 2
)
 

QPS(每秒查询率)

promql
 
 
 
 
 
sum(increase(ent_credit_api_query_http_requests_timer_seconds_count{job="your_job_name"}[1d])) by (prodCode)
/
86400
 

总请求占比

promql
 
 
 
 
 
sum(increase(ent_credit_api_query_http_requests_timer_seconds_count{job="your_job_name"}[1d])) by (prodCode)
/
sum(increase(ent_credit_api_query_http_requests_timer_seconds_count{job="your_job_name"}[1d]))
 

这些查询语句利用了 Prometheus 的 increase 函数来计算当天内指标的增量,从而实现按天统计的目的。同时,通过 summinmaxhistogram_quantile 等函数分别计算不同的统计指标,并按 orgCode 和 prodCode 进行分组。记得将 your_job_name 替换为实际的作业名称。
 
 
如何在 Grafana 中可视化这些统计结果?
 
在 Grafana 中可视化前面统计的结果,可以按照以下详细步骤操作:

1. 登录 Grafana 并创建仪表盘

  • 登录:打开浏览器,访问 Grafana 的 Web 界面,使用你的用户名和密码登录。
  • 创建仪表盘
    • 点击左侧菜单栏中的 “+” 图标,选择 “Dashboard” 来创建一个新的仪表盘。
    • 在弹出的对话框中,点击 “Add an empty panel” 添加一个空白面板。

2. 配置数据源

  • 确保你已经在 Grafana 中添加了 Prometheus 作为数据源。如果还未添加,可以按以下步骤操作:
    • 点击左侧菜单栏中的 “Configuration”(齿轮图标),选择 “Data Sources”。
    • 点击 “Add data source”,选择 “Prometheus”。
    • 配置 Prometheus 的 URL 等信息,然后点击 “Save & Test” 确保连接成功。

3. 为每个指标添加查询并配置可视化方式

成功请求数量和失败请求数量

  • 添加查询
    • 在面板的编辑界面,点击 “Query” 选项卡。
    • 选择之前添加的 Prometheus 数据源。
    • 分别输入成功请求数量和失败请求数量的查询语句,例如按 orgCode 维度统计的成功请求数量:

promql
 
 
 
 
 
sum(increase(ent_credit_api_query_http_requests_success_total{job="your_job_name"}[1d])) by (orgCode)
 

  • 失败请求数量查询语句类似,只需将 success 改为 failure
  • 选择可视化类型:可以选择 “Bar chart”(柱状图)或 “Table”(表格)。
    • 柱状图:能直观地比较不同 orgCode 或 prodCode 的成功和失败请求数量。在 “Visualization” 选项卡中选择 “Bar chart”,根据需要调整图表的颜色、标签等样式。
    • 表格:适合展示详细的数据。选择 “Table”,可以看到每个 orgCode 或 prodCode 对应的具体请求数量。

最小耗时、最大耗时和平均耗时

  • 添加查询:分别输入相应的查询语句,如按 prodCode 维度统计的平均耗时:

promql
 
 
 
 
 
sum(increase(ent_credit_api_query_http_requests_timer_seconds_sum{job="your_job_name"}[1d])) by (prodCode)
/
sum(increase(ent_credit_api_query_http_requests_timer_seconds_count{job="your_job_name"}[1d])) by (prodCode)
 

  • 选择可视化类型:“Line chart”(折线图)或 “Table”。
    • 折线图:可以清晰地展示不同 orgCode 或 prodCode 的耗时随时间的变化趋势(如果数据有时间序列)。在 “Visualization” 选项卡中选择 “Line chart”,调整线条颜色、样式等。
    • 表格:用于查看具体的耗时数值。

95% 耗时和 99% 耗时

  • 添加查询:输入对应的查询语句,如按 orgCode 维度统计的 95% 耗时:

promql
 
 
 
 
 
histogram_quantile(0.95, sum(increase(ent_credit_api_query_http_requests_timer_seconds_bucket{job="your_job_name"}[1d])) by (le, orgCode))
 

  • 选择可视化类型:与最小、最大、平均耗时类似,可以选择 “Line chart” 或 “Table”。

标准差

  • 添加查询:输入标准差的查询语句,如按 prodCode 维度统计:

promql
 
 
 
 
 
sqrt(
  (sum(increase(ent_credit_api_query_http_requests_timer_seconds_sum_of_squares{job="your_job_name"}[1d])) by (prodCode)
  / sum(increase(ent_credit_api_query_http_requests_timer_seconds_count{job="your_job_name"}[1d])) by (prodCode))
  -
  (sum(increase(ent_credit_api_query_http_requests_timer_seconds_sum{job="your_job_name"}[1d])) by (prodCode)
  / sum(increase(ent_credit_api_query_http_requests_timer_seconds_count{job="your_job_name"}[1d])) by (prodCode)) ^ 2
)
 

  • 选择可视化类型:“Line chart” 或 “Table”。

QPS(每秒查询率)

  • 添加查询:输入 QPS 的查询语句,如按 orgCode 维度统计:

promql
 
 
 
 
 
sum(increase(ent_credit_api_query_http_requests_timer_seconds_count{job="your_job_name"}[1d])) by (orgCode)
/
86400
 

  • 选择可视化类型:“Line chart” 能较好地展示 QPS 的变化趋势,“Table” 可查看具体数值。

总请求占比

  • 添加查询:输入总请求占比的查询语句,如按 prodCode 维度统计:

promql
 
 
 
 
 
sum(increase(ent_credit_api_query_http_requests_timer_seconds_count{job="your_job_name"}[1d])) by (prodCode)
/
sum(increase(ent_credit_api_query_http_requests_timer_seconds_count{job="your_job_name"}[1d]))
 

  • 选择可视化类型:“Pie chart”(饼图)可以直观地展示不同 orgCode 或 prodCode 的总请求占比情况,也可以选择 “Table” 查看具体占比数值。

4. 调整面板样式和布局

  • 样式调整:在 “Visualization” 选项卡中,可以调整图表的颜色、字体、轴标签、图例等样式,使图表更加美观和易读。
  • 布局调整:在仪表盘界面,可以通过拖动面板来调整它们的位置和大小,还可以添加行和列来组织面板,使整个仪表盘布局更加合理。

5. 保存仪表盘

完成所有配置后,点击面板右上角的 “Save” 按钮保存面板,再点击仪表盘右上角的 “Save dashboard” 保存整个仪表盘。

通过以上步骤,你就可以在 Grafana 中可视化按照 orgCode 和 prodCode 两个维度统计的各项指标。
 
PromQL 求和,ent_credit_api_query_http_requests_success_total + ent_credit_api_query_http_requests_failure_total
 
在 PromQL 中,要对 ent_credit_api_query_http_requests_success_total 和 ent_credit_api_query_http_requests_failure_total 这两个指标求和,可以使用 sum 函数以及 + 运算符。以下是具体的查询语句示例:

promql
 
 
 
 
 
sum(ent_credit_api_query_http_requests_success_total + ent_credit_api_query_http_requests_failure_total) by (orgCode, prodCode)
 

上述查询语句中:

  • ent_credit_api_query_http_requests_success_total + ent_credit_api_query_http_requests_failure_total 表示将成功请求数量指标和失败请求数量指标相加。
  • sum(...) by (orgCode, prodCode) 表示对相加后的结果按照 orgCode 和 prodCode 这两个标签维度进行分组求和。

如果你不想按照特定标签维度分组,只是单纯地对所有实例的这两个指标求和,可以去掉 by 子句,如下所示:

promql
 
 
 
 
 
sum(ent_credit_api_query_http_requests_success_total + ent_credit_api_query_http_requests_failure_total)
 

这样就会得到所有实例的成功请求数量和失败请求数量的总和。
 
如果 ent_credit_api_query_http_requests_failure_total 或者 ent_credit_api_query_http_requests_success_total 不存在则表示 0
 
在 PromQL 中,当 ent_credit_api_query_http_requests_failure_total 或者 ent_credit_api_query_http_requests_success_total 不存在时希望将其视为 0 进行求和,可以使用 or 操作符来处理这种情况。

按 orgCode 和 prodCode 维度分组求和

promql
 
 
 
 
 
sum(
    (ent_credit_api_query_http_requests_success_total or vector(0)) 
    + 
    (ent_credit_api_query_http_requests_failure_total or vector(0))
) by (orgCode, prodCode)
 

代码解释

  • or 操作符or 操作符用于合并两个向量。如果左边的向量中某个时间序列存在,则使用该时间序列;如果不存在,则使用右边的向量。
  • vector(0)vector(0) 用于创建一个值为 0 的单元素向量。当 ent_credit_api_query_http_requests_success_total 或者 ent_credit_api_query_http_requests_failure_total 不存在对应的时间序列时,就会用 vector(0) 来替代,从而保证在计算时缺失的指标按 0 处理。
  • sum(...) by (orgCode, prodCode):对合并和相加后的结果按照 orgCode 和 prodCode 这两个标签维度进行分组求和。

不分组直接求和

如果你不需要按照特定标签维度分组,只是单纯地对所有实例的这两个指标求和,可以去掉 by 子句:

promql
 
 
 
 
 
sum(
    (ent_credit_api_query_http_requests_success_total or vector(0)) 
    + 
    (ent_credit_api_query_http_requests_failure_total or vector(0))
)
 

这样就能得到所有实例的成功请求数量和失败请求数量的总和,并且在指标不存在时按 0 处理。
 
如何使用PromQL在Grafana中进行数据过滤?
 
在 Grafana 中使用 PromQL 进行数据过滤,可以通过对指标的标签(labels)进行筛选、使用逻辑运算符、范围选择器等多种方式来实现。以下是一些常见的数据过滤方法及示例:

1. 通过标签进行过滤

假设你有一个名为 http_requests_total 的指标,它带有 method(请求方法)和 status(响应状态码)等标签,你可以通过指定标签的值来过滤数据。

  • 过滤特定请求方法的请求数量

promql
 
 
 
 
 
http_requests_total{method="GET"}
 

这条语句会返回所有 method 标签值为 "GET" 的 http_requests_total 指标数据。

  • 过滤特定状态码的请求数量

promql
 
 
 
 
 
http_requests_total{status="200"}
 

这将返回所有 status 标签值为 "200" 的 http_requests_total 指标数据。

  • 组合多个标签进行过滤

promql
 
 
 
 
 
http_requests_total{method="POST", status="404"}
 

此语句会返回 method 为 "POST" 且 status 为 "404" 的 http_requests_total 指标数据。

2. 使用正则表达式进行标签值过滤

如果想匹配符合某种模式的标签值,可以使用正则表达式。

promql
 
 
 
 
 
http_requests_total{method=~"GET|POST", status=~"2.."}
 

上述语句中,method=~"GET|POST" 表示 method 标签的值为 "GET" 或者 "POST"status=~"2.." 表示 status 标签的值以 "2" 开头的任意...
 
 
在 Grafana 中 一般 用什么图形或者表格 展示 上述 最小耗时,最大耗时,平均耗时 等等?
 
在 Grafana 中,针对最小耗时、最大耗时、平均耗时等不同类型的指标,可以选择合适的图形或表格进行展示,以下是一些常见的选择及适用场景:

1. 表格(Table)

  • 适用场景:当你需要精确查看每个分组(如不同的 orgCode 和 prodCode)对应的具体指标数值时,表格是一个很好的选择。它能清晰地展示每一行数据的详细信息,便于对比和分析。
  • 配置示例:在 Grafana 面板中选择 “Table” 可视化类型,将查询到的最小耗时、最大耗时、平均耗时等指标添加到表格中。可以设置表头来明确各列代表的含义,还能对数据进行排序、格式化等操作。

2. 柱状图(Bar Chart)

  • 适用场景:适合比较不同分组之间的指标差异。例如,对比不同 orgCode 或 prodCode 的平均耗时,柱状图可以直观地展示出各个分组的指标大小关系,一眼看出哪个分组的耗时较长或较短。
  • 配置示例:在面板中选择 “Bar Chart”,将分组字段(如 orgCode 或 prodCode)设置为 X 轴,最小耗时、最大耗时、平均耗时等指标分别设置为不同的系列(Y 轴)。可以调整柱子的颜色、宽度等样式,使图表更加美观。

3. 折线图(Line Chart)

  • 适用场景:如果数据具有时间序列特征,例如你想观察最小耗时、最大耗时、平均耗时随时间的变化趋势,折线图是最佳选择。它能够清晰地展示指标的波动情况和发展趋势。
  • 配置示例:在面板中选择 “Line Chart”,将时间字段设置为 X 轴,不同的指标(最小耗时、最大耗时、平均耗时)设置为不同的线条(Y 轴)。可以调整线条的颜色、样式、平滑度等,还能添加数据点标记,方便查看具体数值。

4. 仪表盘(Gauge)

  • 适用场景:当你只关注单个指标的当前值,并且希望以一种直观的方式展示该指标是否处于正常范围时,仪表盘很合适。例如,单独展示某个 orgCode 和 prodCode 组合的平均耗时,并设置一个合理的阈值范围,通过仪表盘的指针位置和颜色变化来快速判断指标是否正常。
  • 配置示例:在面板中选择 “Gauge”,将需要展示的指标(如平均耗时)设置为值字段。可以设置仪表盘的最小值、最大值、阈值范围等参数,还能调整仪表盘的颜色、样式等。

5. 热力图(Heatmap)

  • 适用场景:如果需要同时展示多个分组和多个指标之间的关系,并且想要直观地看到数据的分布和变化趋势,热力图是一个不错的选择。例如,展示不同 orgCode 和 prodCode 组合下的平均耗时,通过颜色深浅来表示耗时的高低。
  • 配置示例:在面板中选择 “Heatmap”,将分组字段(如 orgCode 和 prodCode)分别设置为 X 轴和 Y 轴,平均耗时等指标作为值字段。可以调整颜色映射、数据聚合方式等参数,使热力图更加清晰易懂。
 
 
ent_credit_api_query_http_requests_timer_seconds_bucket 不存在
 
如果 ent_credit_api_query_http_requests_timer_seconds_bucket 指标不存在,可能是由多种原因导致的,下面为你详细分析并给出相应的解决办法。

可能的原因及解决办法

1. 代码未正确记录指标

  • 原因:在 Spring Boot 应用里,若没有正确配置或者使用 Micrometer 来记录计时指标,就不会生成对应的 _bucket 指标。
  • 解决办法
    • 要保证在 Controller 代码中正确使用 Timer 来记录请求耗时。示例代码如下:

java
 
 
 
 
 
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@RestController
public class MyController {

    private final MeterRegistry meterRegistry;

    @Autowired
    public MyController(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
    }

    @GetMapping("/myEndpoint")
    public String myEndpoint(@RequestParam(required = false) String orgCode, @RequestParam(required = false) String prodCode) {
        orgCode = orgCode != null ? orgCode : "unknown";
        prodCode = prodCode != null ? prodCode : "unknown";

        Timer timer = meterRegistry.timer("ent_credit_api_query_http_requests_timer", "orgCode", orgCode, "prodCode", prodCode);
        Timer.Sample sample = Timer.start(meterRegistry);

        try {
            // 模拟业务逻辑
            Thread.sleep((long) (Math.random() * 100));
            return "Success";
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return "Failure";
        } finally {
            sample.stop(timer);
        }
    }
}
 

  • 确保 Micrometer 配置正确,并且在 application.properties 或 application.yml 中启用了 HTTP 请求计时:

properties
 
 
 
 
 
management.metrics.web.server.request.autotime.enabled=true
 

2. 指标还未生成

  • 原因:如果应用刚启动不久,可能还没有足够的请求来生成 _bucket 指标。因为 _bucket 指标是基于直方图的,需要有一定数量的请求数据才能生成。
  • 解决办法
    • 发送一些测试请求到应用,等待一段时间,让指标有足够的数据来生成。你可以使用工具(如 curl 或 Postman)发送多个请求进行测试。

3. Prometheus 配置问题

  • 原因:Prometheus 可能没有正确配置来收集应用的指标,或者收集间隔设置过长,导致指标没有及时被采集。
  • 解决办法
    • 检查 Prometheus 的 prometheus.yml 配置文件,确保正确配置了 Spring Boot 应用的目标地址和采集路径。示例配置如下:

yaml
 
 
 
 
 
scrape_configs:
  - job_name: 'spring-boot-app'
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets: ['localhost:8080']
 

  • 可以适当缩短采集间隔,例如将 scrape_interval 设置为 15s:

yaml
 
 
 
 
 
global:
  scrape_interval: 15s
 

4. 指标名称拼写错误

  • 原因:在 PromQL 查询中,可能存在指标名称拼写错误,导致无法找到对应的指标。
  • 解决办法
    • 仔细检查 PromQL 查询语句中的指标名称,确保与实际的指标名称一致。可以通过访问 Prometheus 的 Web 界面(默认地址为 http://localhost:9090),在 “Graph” 标签页中使用自动补全功能来确认指标名称。

5. 依赖版本不兼容

  • 原因:使用的 Micrometer、Spring Boot 或 Prometheus 客户端库的版本不兼容,可能会导致指标记录或采集出现问题。
  • 解决办法
    • 确保使用的依赖版本相互兼容。可以参考官方文档或社区论坛来选择合适的版本。例如,对于 Spring Boot 3.x,建议使用 Micrometer 1.11.x 系列的版本。

通过以上步骤,你应该能够解决 ent_credit_api_query_http_requests_timer_seconds_bucket 指标不存在的问题。如果问题仍然存在,建议查看应用的日志文件,以获取更多的错误信息。
 
 
management.metrics.web.server.request.autotime.enabled=true 提示 Whether to automatically time web server requests. Deprecated: Requests are timed automatically. DO NOT USE THIS PROPERTY AS IT IS COMPLETELY UNSUPPORTED Default value: true
 
从你给出的提示信息可知,management.metrics.web.server.request.autotime.enabled 这个配置项已被弃用,因为现在 Spring Boot 会自动对 Web 服务器请求进行计时,所以不需要再使用这个配置项。

处理办法

移除配置项

你可以直接从 application.properties 或者 application.yml 里把 management.metrics.web.server.request.autotime.enabled=true 这一行配置删掉。

  • application.properties
    如果原本的配置文件是这样的:

properties
 
 
 
 
 
# 其他配置...
management.metrics.web.server.request.autotime.enabled=true
 

那么修改后变为:

properties
 
 
 
 
 
# 其他配置...
 

  • application.yml
    如果原本的配置文件是这样的:

yaml
 
 
 
 
 
# 其他配置...
management:
  metrics:
    web:
      server:
        request:
          autotime:
            enabled: true
 

那么修改后变为:

yaml
 
 
 
 
 
# 其他配置...
 

验证计时功能

移除配置项之后,你可以验证下计时功能是否正常工作。你可以发送一些请求到你的 Spring Boot 应用,然后通过 Prometheus 的 Web 界面(通常是 http://localhost:9090)来查看是否有相关的计时指标(像 ent_credit_api_query_http_requests_timer_seconds_bucket 这类)。

示例代码验证

以下是一个简单的示例代码,用来验证计时功能:

java
 
 
 
 
 
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@RestController
public class TestController {

    private final MeterRegistry meterRegistry;

    @Autowired
    public TestController(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
    }

    @GetMapping("/test")
    public String test() {
        Timer timer = meterRegistry.timer("ent_credit_api_query_http_requests_timer");
        Timer.Sample sample = Timer.start(meterRegistry);

        try {
            // 模拟一些耗时操作
            TimeUnit.MILLISECONDS.sleep(200);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            sample.stop(timer);
        }

        return "Test completed";
    }
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

发送请求到 /test 端点,然后查看 Prometheus 里是否有 ent_credit_api_query_http_requests_timer_seconds_bucket 指标。
 
prometheus 实现 springboot 某个http post 请求,按照入参 的 两个维度 name 和 age, 统计 http请求耗时。
 
要使用 Prometheus 对 Spring Boot 应用中某个 HTTP POST 请求按照入参的两个维度(name 和 age)统计请求耗时,你可以按照以下步骤进行操作:

1. 添加依赖

在 pom.xml 中添加必要的依赖:

xml
 
 
 
 
 
<dependencies>
    <!-- Spring Boot Actuator -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <!-- Micrometer Registry Prometheus -->
    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-registry-prometheus</artifactId>
    </dependency>
    <!-- Spring Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>
 

2. 配置 Prometheus 端点

在 application.properties 中添加以下配置,以暴露 Prometheus 指标端点:

properties
 
 
 
 
 
management.endpoints.web.exposure.include=prometheus
 

3. 编写控制器和指标统计代码

创建一个控制器类,在其中处理 HTTP POST 请求并使用 Micrometer 统计请求耗时:

java
 
 
 
 
 
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@RestController
public class MyController {

    private final MeterRegistry meterRegistry;

    public MyController(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
    }

    @PostMapping("/my-post-endpoint")
    public String handlePostRequest(@RequestParam String name, @RequestParam int age) {
        // 创建一个带有 name 和 age 标签的计时器
        Timer timer = meterRegistry.timer("http.post.request.time", "name", name, "age", String.valueOf(age));

        long startTime = System.nanoTime();

        // 模拟一些处理逻辑
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        long endTime = System.nanoTime();
        long duration = endTime - startTime;

        // 记录请求耗时
        timer.record(duration, TimeUnit.NANOSECONDS);

        return "Request processed successfully";
    }
}
 

4. 启动 Spring Boot 应用

启动 Spring Boot 应用后,你可以通过以下 URL 访问 Prometheus 指标端点:

plaintext
 
 
 
 
 
http://localhost:8080/actuator/prometheus
 

5. 配置 Prometheus 抓取指标

在 Prometheus 的配置文件 prometheus.yml 中添加以下配置,以从 Spring Boot 应用中抓取指标:

yaml
 
 
 
 
 
scrape_configs:
  - job_name: 'spring-boot-app'
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets: ['localhost:8080']
 

6. 启动 Prometheus

启动 Prometheus 并访问其 Web 界面(通常是 http://localhost:9090),你可以使用以下 PromQL 查询来查看按照 name 和 age 维度统计的请求耗时:

plaintext
 
 
 
 
 
http_post_request_time_seconds_sum{name="your_name", age="your_age"} / http_post_request_time_seconds_count{name="your_name", age="your_age"}
 

通过以上步骤,你就可以使用 Prometheus 对 Spring Boot 应用中某个 HTTP POST 请求按照入参的 name 和 age 两个维度统计请求耗时。
 
 
上面能 统计 请求次数,和 按照两个维度(name 和 age) 的请求占比吗?
 
可以在上述代码基础上进一步统计请求次数以及按照 name 和 age 两个维度的请求占比。下面为你详细介绍实现方法:

1. 统计请求次数

在控制器中,可以使用 Counter 来统计每个 name 和 age 组合的请求次数。

java
 
 
 
 
 
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@RestController
public class MyController {

    private final MeterRegistry meterRegistry;

    public MyController(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
    }

    @PostMapping("/my-post-endpoint")
    public String handlePostRequest(@RequestParam String name, @RequestParam int age) {
        // 创建一个带有 name 和 age 标签的计时器,用于统计请求耗时
        Timer timer = meterRegistry.timer("http.post.request.time", "name", name, "age", String.valueOf(age));
        // 创建一个带有 name 和 age 标签的计数器,用于统计请求次数
        Counter counter = meterRegistry.counter("http.post.request.count", "name", name, "age", String.valueOf(age));

        long startTime = System.nanoTime();

        // 模拟一些处理逻辑
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        long endTime = System.nanoTime();
        long duration = endTime - startTime;

        // 记录请求耗时
        timer.record(duration, TimeUnit.NANOSECONDS);
        // 增加请求计数
        counter.increment();

        return "Request processed successfully";
    }
}
 

2. 计算请求占比

请求占比可以通过 PromQL 在 Prometheus 中进行计算。具体思路是先计算每个 name 和 age 组合的请求次数,再计算总请求次数,最后用每个组合的请求次数除以总请求次数得到占比。

计算每个 name 和 age 组合的请求次数

在 Prometheus 的查询界面,可以使用以下 PromQL 查询每个 name 和 age 组合的请求次数:

plaintext
 
 
 
 
 
http_post_request_count
 

计算总请求次数

可以使用 sum 函数对所有 name 和 age 组合的请求次数求和,得到总请求次数:

plaintext
 
 
 
 
 
sum(http_post_request_count)
 
 
 
 
 
 
 

计算请求占比

将每个 name 和 age 组合的请求次数除以总请求次数,即可得到请求占比:

plaintext
 
 
 
 
 
http_post_request_count / sum(http_post_request_count)
 
 
 
 
 
 
 

3. 注意事项

  • 数据准确性:请求占比的计算结果可能会受到 Prometheus 抓取间隔和数据保留策略的影响。为了获得更准确的结果,可以适当调整 Prometheus 的配置。
  • 性能影响:使用 Counter 和 Timer 会对应用的性能产生一定的影响,尤其是在高并发场景下。可以根据实际情况进行性能测试和优化。

通过以上步骤,你可以统计请求次数并计算按照 name 和 age 两个维度的请求占比。
 
 
posted @ 2025-05-08 15:05  CharyGao  阅读(269)  评论(0)    收藏  举报