一、问题

一个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),@AutowiredMeterRegistry bean。去掉新增的@Autowired JVM相关指标就正常暴露了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Configuration
@MapperScan(value = { "com.**" }, sqlSessionFactoryRef = MybatisConfig.SQL_SESSION_FACTORY, sqlSessionTemplateRef = MybatisConfig.SQL_SESSION_TEMPLATE)
@EnableConfigurationProperties(DynamicDataSourceProperties.class)
public class MybatisConfig {
public static final String SQL_SESSION_FACTORY = "mainSqlSessionFactory";
public static final String SQL_SESSION_TEMPLATE = "mainSqlSessionTemplate";

@Autowired
private MeterRegistry meterRegistry;

@Bean(SQL_SESSION_FACTORY)
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource);
...
sessionFactoryBean.setPlugins(new SqlMonitorInterceptor(meterRegistry));
...

那么@Autowired一个MeterRegistry类咋就造成jvm_memory_used_bytes指标丢了呢?

这个跟Spring Boot的ConfigurationAutoConfiguration bean的初始化顺序有关。

简单来说,自定义的@Configuration 类优先级高于所有 Starter 的自动配置类。我们场景中prometheus指标正是通过MetricsAutoConfigurationJvmMetricsAutoConfiguration自动装配实现的。

我们自定义的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创建的)。