Spring Boot中prometheus指标中缺失了JVM相关指标
一、问题
一个Spring Boot应用已经在配置中通过actuator和micrometer暴露了prometheus端点http://ip:port/actuator/prometheus,结合prometheus和grafana已使用在线上监控系统中了。
最近几周发现通过 /actuator/prometheus仍然能访问应用暴露的prometheus监控端点和部分指标,但是JVM相关的指标比如jvm_memory_used_bytes不见了,造成监控缺失。
二、原因
actuator、micrometer、prometheus和grafna最近配置没有做过调整。
看了一下应用最近的变更,在MyBatis自定义Configuration Bean中因为要定义SqlSessionFactory的Plugin(SQL Interceptor),@Autowired了MeterRegistry bean。去掉新增的@Autowired JVM相关指标就正常暴露了。
1 | @Configuration |
那么@Autowired一个MeterRegistry类咋就造成jvm_memory_used_bytes指标丢了呢?
这个跟Spring Boot的Configuration和AutoConfiguration bean的初始化顺序有关。
简单来说,自定义的@Configuration 类优先级高于所有 Starter 的自动配置类。我们场景中prometheus指标正是通过MetricsAutoConfiguration和JvmMetricsAutoConfiguration自动装配实现的。
我们自定义的MybatisConfig先初始化,初始化sqlSessionFactory bean的时候提前触发了MeterRegistry的初始化。但是这时候初始化的MeterRegistry是默认实现SimpleMeterRegistry,这个默认实现是不包括JVM指标的。等到MetricsAutoConfiguration初始化时,@ConditionalOnMissingBean(MeterRegistry.class)不匹配,就不会再初始化和配置MeterRegistry实例了。
三、解决
解决的方法是MybatisConfig初始化时不立刻创建 MeterRegistry,只注入一个代理。这可以通过在MybatisConfig类定义中针对meterRegistry添加@Lazy注解来实现。
1
2
3@Autowired
@Lazy
private MeterRegistry meterRegistry;
当 SqlMonitorInterceptor 最终使用 meterRegistry 时,取到的就是一个已经绑定了 JVM metrics 的 MeterRegistry(MetricsAutoConfiguration创建的)。