Micrometer自定义指标在Docker容器中多数返回0问题求助
自定义Prometheus指标在Docker容器中异常问题排查与解决
我需要在Spring Boot应用中添加自定义指标,并暴露在/actuator/prometheus路径下。本地调试时指标显示正常,但部署到Docker容器后,自定义指标my_load的结果大多为0.0,多次重启容器偶尔能得到非0值。怀疑是初始化阶段存在竞态条件,按照建议将OperatingSystemMXBean改为类成员后,容器内运行可稳定获取非0指标值。
原实现代码
@SpringBootApplication public class CustomMetricsApplication { public static void main(String[] args) { SpringApplication.run(CustomMetricsApplication.class, args); } @RestController static class MyController { @GetMapping("/metrics") public List<Double> getMetrics() { List<Double> result = new ArrayList<>(); for (int i = 0; i < 10; i++) { result.add(Math.random() * 100); } return result; } } } @Configuration public class MetricsConfig { @Bean MeterBinder getLoadMeter() { return new LoadMetric(); } } public class LoadMetric implements MeterBinder { private static final Logger logger = LoggerFactory.getLogger(LoadMetric.class); @Override public void bindTo(MeterRegistry meterRegistry) { Tags tags = Tags.of("application", "panda"); meterRegistry.gauge("my_load", tags, this, LoadMetric::calculateMetricValue); } private double calculateMetricValue() { OperatingSystemMXBean osBean = ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class); double metricValue = osBean.getProcessCpuLoad() * 100.0; logger.info("Value {}", metricValue); return metricValue; } }
Dockerfile配置
FROM eclipse-temurin:17.0.7_7-jre-alpine RUN mkdir -p /services/ COPY target/custom-metrics-1.0.0.jar /services CMD java -XX:MinRAMPercentage=40.0 -XX:MaxRAMPercentage=80.0 -XX:+HeapDumpOnOutOfMemoryError -jar /services/custom-metrics-1.0.0.jar
修改后运行日志
2023-06-13T06:33:31.370Z INFO 1 --- [nio-8080-exec-1] c.happypanda.custommetrics.LoadMetric : Value 0.0 2023-06-13T06:33:32.683Z INFO 1 --- [nio-8080-exec-3] c.happypanda.custommetrics.LoadMetric : Value 3.2380952380952377 2023-06-13T06:33:36.347Z INFO 1 --- [nio-8080-exec-4] c.happypanda.custommetrics.LoadMetric : Value 0.25 2023-06-13T06:33:38.673Z INFO 1 --- [nio-8080-exec-5] c.happypanda.custommetrics.LoadMetric : Value 0.07171029042667623 2023-06-13T06:33:41.188Z INFO 1 --- [nio-8080-exec-6] c.happypanda.custommetrics.LoadMetric : Value 0.09953550099535502 2023-06-13T06:33:43.564Z INFO 1 --- [nio-8080-exec-7] c.happypanda.custommetrics.LoadMetric : Value 0.14020329477742727 2023-06-13T06:33:48.971Z INFO 1 --- [nio-8080-exec-8] c.happypanda.custommetrics.LoadMetric : Value 0.046289152908501774 2023-06-13T06:34:04.070Z INFO 1 --- [nio-8080-exec-9] c.happypanda.custommetrics.LoadMetric : Value 0.022086025067638453 2023-06-13T06:34:05.289Z INFO 1 --- [io-8080-exec-10] c.happypanda.custommetrics.LoadMetric : Value 0.06839945280437756 2023-06-13T06:34:08.793Z INFO 1 --- [nio-8080-exec-2] c.happypanda.custommetrics.LoadMetric : Value 0.07137758743754462 2023-06-13T06:34:11.564Z INFO 1 --- [nio-8080-exec-1] c.happypanda.custommetrics.LoadMetric : Value 0.060168471720818295 2023-06-13T06:34:16.481Z INFO 1 --- [nio-8080-exec-3] c.happypanda.custommetrics.LoadMetric : Value 0.05089058524173028 2023-06-13T06:34:17.761Z INFO 1 --- [nio-8080-exec-4] c.happypanda.custommetrics.LoadMetric : Value 0.13063357282821686 2023-06-13T06:34:19.803Z INFO 1 --- [nio-8080-exec-5] c.happypanda.custommetrics.LoadMetric : Value 0.12239902080783352 2023-06-13T06:34:20.936Z INFO 1 --- [nio-8080-exec-6] c.happypanda.custommetrics.LoadMetric : Value 0.14705882352941177 2023-06-13T06:34:21.901Z INFO 1 --- [nio-8080-exec-7] c.happypanda.custommetrics.LoadMetric : Value 0.17286084701815038 2023-06-13T06:40:00.641Z INFO 1 --- [io-8080-exec-10] c.happypanda.custommetrics.LoadMetric : Value 0.011319510406567285
问题原因与解决方案
- 问题原因:原代码中每次计算指标时都通过
ManagementFactory.getPlatformMXBean()获取新的OperatingSystemMXBean实例,在Docker容器环境下,JVM初始化阶段的资源竞争可能导致获取的Bean无法正确采集CPU负载数据,返回0.0。 - 解决方案:将
OperatingSystemMXBean改为类成员变量,在类初始化时就获取实例并复用,避免重复获取带来的竞态问题,确保指标采集稳定。
修改后的LoadMetric代码如下:
public class LoadMetric implements MeterBinder { private static final Logger logger = LoggerFactory.getLogger(LoadMetric.class); // 改为类成员,初始化时获取实例 private final OperatingSystemMXBean osBean = ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class); @Override public void bindTo(MeterRegistry meterRegistry) { Tags tags = Tags.of("application", "panda"); meterRegistry.gauge("my_load", tags, this, LoadMetric::calculateMetricValue); } private double calculateMetricValue() { double metricValue = osBean.getProcessCpuLoad() * 100.0; logger.info("Value {}", metricValue); return metricValue; } }
内容的提问来源于stack exchange,提问作者florin
相关产品推荐
相关产品推荐

