You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Java+Apache Commons Math计算随时间变化的平均请求时长

实现随时间变化的平均请求时长(仿Prometheus rate计算逻辑)

核心逻辑说明

Prometheus中rate(http_server_requests_seconds_sum[5m]) / rate(http_server_requests_seconds_count[5m])的本质是:取指定时间窗口内的总请求时长,除以该窗口内的总请求数。因为rate(sum)是窗口总时长除以窗口时间(得到每秒总时长速率),rate(count)是窗口总请求数除以窗口时间(得到每秒请求数速率),两者相除后窗口时间抵消,最终结果就是窗口内的平均请求时长。

Java实现方案

由于你之前用EmpiricalDistribution仅统计了请求时间的分桶请求数,现在需要同时统计每个时间桶内的请求数和请求时长总和,才能计算平均时长。以下是适配你离线数据集的实现代码:

1. 定义桶统计数据类

用来存储每个时间桶的关键指标:

class BucketStats {
    private final long startTimeMs;
    private final long endTimeMs;
    private long requestCount;
    private double totalDurationSec;

    public BucketStats(long startTimeMs, long endTimeMs) {
        this.startTimeMs = startTimeMs;
        this.endTimeMs = endTimeMs;
        this.requestCount = 0;
        this.totalDurationSec = 0.0;
    }

    public void recordRequest(double durationSec) {
        requestCount++;
        totalDurationSec += durationSec;
    }

    public double getAverageDurationSec() {
        return requestCount == 0 ? 0.0 : totalDurationSec / requestCount;
    }

    // Getter方法
    public long getStartTimeMs() { return startTimeMs; }
    public long getEndTimeMs() { return endTimeMs; }
    public long getRequestCount() { return requestCount; }
    public double getTotalDurationSec() { return totalDurationSec; }
}

2. 分桶计算逻辑

假设你的原始数据是包含请求时间(毫秒)和请求时长(秒)的列表,按与EmpiricalDistribution一致的桶数进行分桶统计:

// 替换为你的原始请求数据集,Request需包含requestTimeMs和durationSec字段
List<Request> requests = ...;
int bucketCount = ...; // 和之前EmpiricalDistribution使用的桶数保持一致

// 确定时间范围
long minTimeMs = requests.stream().mapToLong(Request::getRequestTimeMs).min().orElse(0);
long maxTimeMs = requests.stream().mapToLong(Request::getRequestTimeMs).max().orElse(0);
long bucketIntervalMs = (maxTimeMs - minTimeMs) / bucketCount;

// 初始化所有时间桶
List<BucketStats> buckets = new ArrayList<>();
for (int i = 0; i < bucketCount; i++) {
    long startTime = minTimeMs + i * bucketIntervalMs;
    long endTime = startTime + bucketIntervalMs;
    // 修正最后一个桶的结束时间,避免超出最大时间
    if (i == bucketCount - 1) {
        endTime = maxTimeMs;
    }
    buckets.add(new BucketStats(startTime, endTime));
}

// 将请求分配到对应桶并统计
for (Request req : requests) {
    long reqTimeMs = req.getRequestTimeMs();
    int bucketIndex = (int) ((reqTimeMs - minTimeMs) / bucketIntervalMs);
    // 处理边界请求,确保索引不越界
    bucketIndex = Math.min(bucketIndex, bucketCount - 1);
    buckets.get(bucketIndex).recordRequest(req.getDurationSec());
}

// 输出或存储每个时间桶的平均请求时长
buckets.stream()
       .filter(stat -> stat.getRequestCount() > 0)
       .forEach(stat -> {
           // 这里替换为你的存储逻辑
           System.out.printf("时间区间: [%dms, %dms] | 平均请求时长: %.4fs | 请求数: %d%n",
                   stat.getStartTimeMs(), stat.getEndTimeMs(),
                   stat.getAverageDurationSec(), stat.getRequestCount());

           // 若要严格对齐Prometheus的rate计算逻辑(验证用)
           double bucketIntervalSec = (stat.getEndTimeMs() - stat.getStartTimeMs()) / 1000.0;
           double rateSum = stat.getTotalDurationSec() / bucketIntervalSec;
           double rateCount = stat.getRequestCount() / bucketIntervalSec;
           double promStyleAvg = rateSum / rateCount;
           System.out.printf("Prometheus风格计算结果: %.4fs%n", promStyleAvg);
       });

3. 与原有EmpiricalDistribution逻辑的兼容

如果你想复用EmpiricalDistribution的分桶边界(避免重新计算时间区间),可以通过dist.getBinStats()获取每个桶的起止范围,再遍历请求数据分配到对应桶:

// 复用你已有的EmpiricalDistribution实例
EmpiricalDistribution dist = ...;
List<BucketStats> buckets = new ArrayList<>();

// 从dist中获取桶的边界并初始化BucketStats
for (SummaryStatistics stat : dist.getBinStats()) {
    // 注意:EmpiricalDistribution的bin是[start, end)区间,时间单位需和你的请求时间一致
    long startTimeMs = (long) stat.getMin();
    long endTimeMs = (long) stat.getMax();
    buckets.add(new BucketStats(startTimeMs, endTimeMs));
}

// 后续的请求分配、统计逻辑和上述一致

内容的提问来源于stack exchange,提问作者Borislav Stoilov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 20:25:17