Quarkus Prometheus百分位指标长期无更新后置零,更新后仍未恢复咨询
问题根因
你遇到的是Micrometer客户端百分位计算的底层机制问题,和Quarkus本身无关:
- 你配置的
distributionStatisticExpiry(Duration.ofMinutes(5))作用是:当5分钟内没有新的样本写入,Timer底层用于计算百分位的滑动窗口缓冲区会被完全回收,而非简单清零。 - count(调用次数)、sum(总耗时)、max(最大耗时)这类指标是全局独立维护的,不受缓冲区回收影响,所以更新后能立即看到最新值。
- 客户端计算的百分位(
publishPercentiles配置项开启)完全依赖滑动窗口缓冲区的数据,缓冲区被回收后首次写入新样本时,需要重新初始化缓冲区。默认distributionStatisticBufferLength值为3,也就是说5分钟的过期时间会被拆分为3个100秒的桶,新写入的样本会进入当前活跃桶,只有当桶被轮转后才会被纳入百分位计算,所以刚更新的短时间内查询百分位会返回0。
另外你的代码存在一处明显笔误:方法入参是String[] tags,但构造Timer时传入的是未定义的newTags,实际运行会编译失败,需要改为.tags(tags)。
可行解决方案
方案1:改用服务端计算百分位(最推荐)
将publishPercentiles(PERCENTILES)替换为publishPercentileHistogram(true),客户端只输出Histogram桶计数,百分位由Prometheus通过histogram_quantile函数在服务端计算。
- 优势:不受客户端缓冲区回收逻辑影响,新样本写入后桶计数立即更新,查询时可以得到正确的百分位数值,同时支持任意时间范围的百分位聚合。
- 示例配置:
Timer newTimer = Timer.builder(timerName) .tags(tags) .publishPercentileHistogram(true) .distributionStatisticExpiry(Duration.ofMinutes(5)) .register(registry);
方案2:调整客户端百分位缓冲配置
如果必须使用客户端计算的百分位,可以在构造Timer时添加distributionStatisticBufferLength(1)配置,将滑动窗口桶数设为1:
Timer newTimer = Timer.builder(timerName) .tags(tags) .publishPercentiles(PERCENTILES) .distributionStatisticExpiry(Duration.ofMinutes(5)) .distributionStatisticBufferLength(1) // 新增配置 .register(registry);
配置后滑动窗口只有一个桶,新样本写入后会立即纳入百分位计算,不会出现零值问题。
方案3:移除自定义的timerMap
Micrometer的register方法本身是幂等的,相同名称+标签的Timer只会注册一次,重复调用会直接返回已存在的实例,不需要自行维护ConcurrentHashMap存储Timer实例,避免自行生成key的逻辑和Micrometer的Meter ID生成逻辑不一致导致的重复注册问题。
内容的提问来源于stack exchange,提问作者mettw
相关产品推荐
相关产品推荐

