Reactor 3.6升级后CPU占用飙升,如何规避上下文传播开销?
将Reactor从3.5版本升级到3.6版本后,相同负载(约200请求/秒)下CPU使用率从平均30%翻倍至60%,峰值达100%。经性能分析,上下文传播的上下文复制调用次数显著增加是核心诱因。
我们使用Slf4j日志框架,通过ThreadLocal实现的MDC存储trace ID及业务自定义ID,并通过Hooks.enableAutomaticContextPropagation()开启自动上下文传播。
版本对比统计数据
Reactor 3.5.18(Reactor BOM 2022.0.20,搭配reactor-core-micrometer 1.0.7)
brave.baggage.CorrelationScopeDecorator$Multiple#decorateScope:286次调用Flux.ContextWriteRestoringThreadLocalsSubscriber#onNext():16次调用Mono.ContextWriteRestoringThreadLocalsSubscriber#onNext():31次调用
Reactor 3.6.7(Reactor BOM 2023.0.2,搭配reactor-core-micrometer 1.0.18)
brave.baggage.CorrelationScopeDecorator$Multiple#decorateScope:649次调用Flux.ContextWriteRestoringThreadLocalsSubscriber#onNext():108次调用Mono.ContextWriteRestoringThreadLocalsSubscriber#onNext():32次调用
可见FluxContextWriteRestoringThreadLocals$ContextWriteRestoringThreadLocalsSubscriber.onNext()与decorateScope的调用次数均大幅上升。
现有优化背景与诉求
此前我们通过Spring Sleuth的decorate on last配置将CPU占用降低了约30%。现在希望:
- 以最小改动完成Spring Boot/Cloud及Reactor版本升级
- 避免CPU占用激增
- 保留3.5版本级别的上下文传播能力(3.6的额外开销无实际业务增益)
额外观测细节
即使Flux在同一线程执行,仍会产生大量上下文复制操作。在测试场景中,通过ContextRegistry...registerThreadLocalAccessor统计MDC.put调用次数,发现版本切换后从27次增至135次。
示例堆栈信息:
[BYTEMAN] org.slf4j.MDC#put(requestId) in thread HttpClient-1-Worker-0 org.slf4j.MDC.put(MDC.java:128) nl.stokpop.performance.reactive.ReactiveDemoStandAlone._init_$lambda$9(ReactiveDemoStandAlone.kt:36) io.micrometer.context.ContextRegistry$1.setValue(ContextRegistry.java:121) io.micrometer.context.DefaultContextSnapshot.setThreadLocal(DefaultContextSnapshot.java:102) io.micrometer.context.DefaultContextSnapshotFactory.setAllThreadLocalsFrom(DefaultContextSnapshotFactory.java:125) io.micrometer.context.DefaultContextSnapshotFactory.setThreadLocalsFrom(DefaultContextSnapshotFactory.java:109) reactor.core.publisher.ContextPropagation.setThreadLocals(ContextPropagation.java:85) reactor.core.publisher.FluxContextWriteRestoringThreadLocals$ContextWriteRestoringThreadLocalsSubscriber.onNext(FluxContextWriteRestoringThreadLocals.java:117) org.reactivestreams.FlowAdapters$FlowToReactiveSubscriber.onNext(FlowAdapters.java:211)
(完整应用中brave.CorrelationScopeDecorator.Multiple#decorateScope的开销更大,但版本升级后的调用次数增长幅度相近)
当前环境与疑问
我们当前使用Spring Boot 3.1.12、Spring Cloud 2022.0.5及Reactor BOM 2022.0.20,该问题已阻碍版本升级。
请问:
- 针对Reactor 3.6,是否有方法减少此类上下文传播相关调用次数?
- 该情况是否属于回归bug?是否有必要在Reactor-core的GitHub仓库提交问题?
内容的提问来源于stack exchange,提问作者Peter Paul Bakker

