为什么Prometheus计算request_duration指标时需要使用rate函数?
核心结论先摆清楚
你觉得这个用法没意义,本质是搞混了*_bucket类直方图指标的存储含义,以及rate()函数在这里的实际作用对象。
先搞懂request_duration_bucket到底存的是什么
server_request_duration_seconds_bucket不是存请求时长数值的指标,它是单调递增的累计计数器:
- 每个时间序列带一个
le标签,对应时长边界,比如le="0.1"代表这个序列记录的是「从服务启动到当前时刻,请求时长小于等于0.1秒的总请求数」 - 只要服务不重启、不重置,这个值只会涨不会跌,存的是服务全生命周期的累计值,不是某段时间的统计值
为什么必须用rate()?不用会怎么样?
histogram_quantile()函数计算分位数的前提,是拿到你要统计的时间窗口内,各个时长区间的请求数量分布,而不是服务从启动到现在的所有历史请求的累计分布:
- 如果直接拿原始的累计bucket值计算,得到的是服务上线以来所有历史请求的p99,服务运行时间越久,新产生的请求对结果的影响越小,根本反映不了最近的服务时延情况,完全没有监控参考价值
rate(server_request_duration_seconds_bucket[1m])在这里根本不是算「请求时长的变化率」,它算的是过去1分钟内,每个le对应的bucket平均每秒新增的请求数——本质是从累计计数器里,提取出最近1分钟这个窗口里,新增请求在各个时长区间的分布比例。- 这里要注意:
histogram_quantile计算分位数只关心各个bucket的数值比例,不关心绝对值是「窗口内总请求数」还是「每秒请求速率」,所以用rate()或者increase()(算窗口内总增量)都可以,最终算出来的分位数结果完全一致,只是大家写PromQL的时候习惯用rate而已。
示例语句逐段解释
histogram_quantile(0.99, sum by (le) (rate(server_request_duration_seconds_bucket[1m])))
- 最内层
rate(xxx[1m]):计算每个实例、每个时长bucket在过去1分钟的请求增长速率,拿到单实例维度的1分钟内请求时延分布 - 中间
sum by (le):把所有实例的相同时长边界的bucket数值加总,聚合成全局维度的时延分布——多实例场景下不加这步,算出来的是每个实例单独的p99,不是整个服务的全局p99 - 最外层
histogram_quantile(0.99, ...):基于聚合后的分布,通过线性插值估算出过去1分钟内全局请求的p99时延
举个反例就懂了
假设你的服务刚上线前10分钟全是慢请求,p99达到5s;之后服务优化完成,连续跑了1小时,所有请求都在100ms以内:
- 如果不用
rate()直接拿累计值算p99,结果会长期被前10分钟的慢请求拉到接近5s,你根本看不到优化后的时延下降 - 用
rate(...[1m])提取最近1分钟的分布算,只要慢请求的时间窗口过去,结果会立刻降到100ms左右,真实反映当前的服务状态
内容的提问来源于stack exchange,提问作者Djvu
相关产品推荐
相关产品推荐

