SpringBoot应用重启后Actuator自定义Prometheus指标重置为0如何解决
解决方案
方案1:PromQL层面处理(优先推荐,改造成本最低)
这是工业界最常用的解决方案,不需要修改应用代码或架构,利用Prometheus内置特性即可处理Counter重置问题
- 你统计的请求计数属于Counter类型指标,PromQL的
rate()、irate()、increase()函数本身已经内置了对Counter重置的处理逻辑:当检测到指标值比前一个样本小的时候,会自动判定Counter发生了重置,计算增量时会自动补上重置前的累计值。 - 示例:如果你之前直接用
your_request_counter_total原始值做图表展示导致骤降,改成用increase(your_request_counter_total[1m])计算1分钟内的请求增量,或者rate(your_request_counter_total[5m])计算平均QPS,就不会出现骤降到0的情况。 - 注意:不要直接把Counter类型的原始值拿来做折线图展示,这类指标的核心用法是统计一段时间的增量、速率,原生函数已经完美适配了应用重启重置的场景。
方案2:应用侧指标持久化(适合需要保留全局累计值的特殊场景)
如果你的业务确实需要展示请求计数的全局累计值,无法用增量/速率替代展示,可以把指标从内存存储改成持久化存储:
- 选择适配业务的持久化介质:单机部署可以用本地RocksDB、嵌入式数据库,分布式部署可以用Redis等共享存储。
- 自定义MeterRegistry实现:继承Micrometer的
SimpleMeterRegistry,重写Counter的存取逻辑,应用启动时从持久化介质读取之前的累计值作为初始值,每次Counter更新时同步写入持久化存储。 - 核心代码示例:
// 基于Redis实现的持久化Counter public class PersistentCounter extends AbstractCounter { private final String counterKey; private final RedisTemplate<String, Long> redisTemplate; public PersistentCounter(Id id, String counterKey, RedisTemplate<String, Long> redisTemplate) { super(id); this.counterKey = counterKey; this.redisTemplate = redisTemplate; } @Override public void increment(double amount) { redisTemplate.opsForValue().increment(counterKey, (long) amount); } @Override public double count() { Long value = redisTemplate.opsForValue().get(counterKey); return value != null ? value.doubleValue() : 0.0; } }
- 注意:多实例部署场景下要给每个实例的指标key添加唯一标识(比如实例IP、Pod名),避免不同实例的计数互相覆盖。
方案3:部署架构层面规避(云原生场景适用)
如果是Kubernetes部署的应用,可以配合发布策略降低重置影响:
- 采用滚动发布策略,新旧实例共存一段时间,Prometheus可以同时抓取新旧实例的指标,避免所有实例同时重置导致指标整体骤降。
- 配合Prometheus服务发现自动剔除下线实例,不需要额外修改指标逻辑。
内容的提问来源于stack exchange,提问作者Healthy Bowl
相关产品推荐
相关产品推荐

