欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 建筑 > 解决SpringBoot 3.3.x集成Micrometer和Prometheus,导致项目阻塞,无法启动

解决SpringBoot 3.3.x集成Micrometer和Prometheus,导致项目阻塞,无法启动

2024/10/25 23:32:18 来源:https://blog.csdn.net/qq_39893313/article/details/142624149  浏览:    关键词:解决SpringBoot 3.3.x集成Micrometer和Prometheus,导致项目阻塞,无法启动

        小伙伴们,你们好,我是老寇,我又回来辣,几个月不见甚是想念啊!!!

使用SpringBoot 3.3.x集成Micrometer和Prometheus,导致项目无法启动,因为集成的组件特别多,具体什么组件有问题,无法得知。但是,作为一名程序员,基本排查问题的思路,还是需要具备的!

排查问题方向

1.版本不兼容【代码冲突】

2.错误使用

因此,按照这两个方向进行排查,首先,排除 错误使用 剩下就是版本问题,因为是引入micrometer-registry-prometheus才导致项目阻塞,而对于组件,一般有两种解决方案,一种是降低版本【治标不治本】,另一种阅读源码,找出具体代码,然后改掉【治本】

所以,就有以下两种解决方案

1.降低micrometer的版本至1.11.12,但是需要注意的是spring boot 3.5会删除 PrometheusSimpleclientMetricsExportAutoConfiguration 因此,这种方式不推荐

1  <dependencies><dependency><groupId>io.micrometer</groupId><artifactId>micrometer-registry-prometheus</artifactId><version>1.11.12</version></dependency></dependencies>

2.直接阅读源码,找出问题的根源,经过我debug,找出造成阻塞的代码。注意,使用ObjectProvider,会延迟加载,需要被实际调用,才会完成初始化

源码里面有这么一段注释,大致意思是:MeterRegistry依赖于Tracer,Tracer又依赖于MeterRegistry,所以通过延迟加载的方式来打破循环

Since the MeterRegistry can depend on the {@link Tracer} (Exemplars) and the {@link Tracer} can depend on the MeterRegistry (recording metrics),

this {@link SpanContext} breaks the cycle by lazily loading the {@link Tracer}.

 注意:ObjectProvider.getObject() 本身不会直接造成项目阻塞,但如果Bean的获取耗时过长,可能会导致调用该方法的线程被阻塞,此外,如果存在循环依赖,还会造成死锁的情况

@AutoConfiguration(before = PrometheusMetricsExportAutoConfiguration.class,after = MicrometerTracingAutoConfiguration.class)
@ConditionalOnBean(Tracer.class)
@ConditionalOnClass({ Tracer.class, SpanContext.class })
public class PrometheusExemplarsAutoConfiguration {@Bean@ConditionalOnMissingBean// 延迟加载SpanContext spanContext(ObjectProvider<Tracer> tracerProvider) {return new LazyTracingSpanContext(tracerProvider);}/*** Since the MeterRegistry can depend on the {@link Tracer} (Exemplars) and the* {@link Tracer} can depend on the MeterRegistry (recording metrics), this* {@link SpanContext} breaks the cycle by lazily loading the {@link Tracer}.*/static class LazyTracingSpanContext implements SpanContext {private final SingletonSupplier<Tracer> tracer;LazyTracingSpanContext(ObjectProvider<Tracer> tracerProvider) {this.tracer = SingletonSupplier.of(tracerProvider::getObject);}@Overridepublic String getCurrentTraceId() {Span currentSpan = currentSpan();return (currentSpan != null) ? currentSpan.context().traceId() : null;}@Overridepublic String getCurrentSpanId() {Span currentSpan = currentSpan();return (currentSpan != null) ? currentSpan.context().spanId() : null;}@Overridepublic boolean isCurrentSpanSampled() {Span currentSpan = currentSpan();if (currentSpan == null) {return false;}Boolean sampled = currentSpan.context().sampled();return sampled != null && sampled;}@Overridepublic void markCurrentSpanAsExemplar() {}private Span currentSpan() {return this.tracer.obtain().currentSpan();}}}

因此,改为直接从IOC容器,获取Bean,源码改动如下

@AutoConfiguration(before = PrometheusMetricsExportAutoConfiguration.class,after = MicrometerTracingAutoConfiguration.class)
@ConditionalOnBean(Tracer.class)
@ConditionalOnClass({ Tracer.class, SpanContext.class })
public class PrometheusExemplarsAutoConfiguration {@Bean@ConditionalOnMissingBeanSpanContext spanContext() {return new TracingSpanContext();}/*** Since the MeterRegistry can depend on the {@link Tracer} (Exemplars) and the* {@link Tracer} can depend on the MeterRegistry (recording metrics), this* {@link SpanContext} breaks the cycle by lazily loading the {@link Tracer}.*/static class TracingSpanContext implements SpanContext {@Overridepublic String getCurrentTraceId() {Span currentSpan = currentSpan();return ObjectUtil.isNotNull(currentSpan) ? currentSpan.context().traceId() : null;}@Overridepublic String getCurrentSpanId() {Span currentSpan = currentSpan();return ObjectUtil.isNotNull(currentSpan) ? currentSpan.context().spanId() : null;}@Overridepublic boolean isCurrentSpanSampled() {Span currentSpan = currentSpan();if (ObjectUtil.isNull(currentSpan)) {return false;}return currentSpan.context().sampled();}@Overridepublic void markCurrentSpanAsExemplar() {}private Span currentSpan() {try {return SpringContextUtil.getBean(Tracer.class).currentSpan();}catch (Exception e) {return null;}}}}

大功告成

这个问题,可是困扰了我好几周呢,中间可是折腾好久,换好多种实现,其中,不外乎换组件,换架构!终于,硬着头皮解决这个问题啦,哈哈哈~

我是老寇,我们后会有期

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com