Reactor项目中使用Sentinel偶尔会出现Context0#put空指针异常

a0zr77ik  于 2022-10-19  发布在  React
关注(0)|答案(2)|浏览(135)

WebFlux项目中导入sentinel-spring-webflux-adapter:1.8.0适配模块,项目每天都有好几个NPE,报错内容如下:

Caused by: java.lang.NullPointerException: value
	at java.util.Objects.requireNonNull(Objects.java:228)
	at reactor.util.context.Context0.put(Context0.java:30)
	at com.alibaba.csp.sentinel.adapter.reactor.SentinelReactorSubscriber.currentContext(SentinelReactorSubscriber.java:70)

对应的源码应该是这一行

return actual.currentContext()
            .put(SentinelReactorConstants.SENTINEL_CONTEXT_KEY, currentEntry.getAsyncContext());

从异常栈信息看,应该是 currentEntry.getAsyncContext() 这句返回了null,但不知为何会出现null

z31licg0

z31licg01#

是否有办法稳定复现?

c0vxltue

c0vxltue2#

是否有办法稳定复现?

我在本地测试了好几种情况,发现结合r2dbc使用时且并发量高的情况下才偶然复现,详细的异常栈信息如下:

2020-12-18-16:35:57 [reactor-tcp-nio-8] ERROR reactor.core.publisher.Operators - Operator called default onErrorDropped
java.lang.NullPointerException: value
	at java.util.Objects.requireNonNull(Objects.java:228)
	at reactor.util.context.Context0.put(Context0.java:30)
	at com.alibaba.csp.sentinel.adapter.reactor.SentinelReactorSubscriber.currentContext(SentinelReactorSubscriber.java:70)
	at reactor.core.publisher.InnerOperator.currentContext(InnerOperator.java:32)
	at reactor.core.publisher.MonoFlatMap$FlatMapInner.currentContext(MonoFlatMap.java:213)
	at reactor.core.publisher.InnerOperator.currentContext(InnerOperator.java:32)
	at reactor.core.publisher.InnerOperator.currentContext(InnerOperator.java:32)
	at reactor.core.publisher.InnerOperator.currentContext(InnerOperator.java:32)
	at reactor.core.publisher.InnerOperator.currentContext(InnerOperator.java:32)
	at reactor.core.publisher.InnerOperator.currentContext(InnerOperator.java:32)
	at reactor.core.publisher.InnerOperator.currentContext(InnerOperator.java:32)
	at reactor.core.publisher.InnerOperator.currentContext(InnerOperator.java:32)
	at reactor.core.publisher.InnerOperator.currentContext(InnerOperator.java:32)
	at reactor.core.publisher.MonoFlatMap$FlatMapInner.currentContext(MonoFlatMap.java:213)
	at reactor.core.publisher.InnerOperator.currentContext(InnerOperator.java:32)
	at reactor.core.publisher.MonoFlatMap$FlatMapInner.currentContext(MonoFlatMap.java:213)
	at reactor.core.publisher.InnerOperator.currentContext(InnerOperator.java:32)
	at reactor.core.publisher.InnerOperator.currentContext(InnerOperator.java:32)
	at reactor.core.publisher.MonoFlatMap$FlatMapInner.currentContext(MonoFlatMap.java:213)
	at reactor.core.publisher.InnerOperator.currentContext(InnerOperator.java:32)
	at reactor.core.publisher.InnerOperator.currentContext(InnerOperator.java:32)
	at reactor.core.publisher.InnerOperator.currentContext(InnerOperator.java:32)
	at reactor.core.publisher.InnerOperator.currentContext(InnerOperator.java:32)
	at reactor.core.publisher.InnerOperator.currentContext(InnerOperator.java:32)
	at reactor.core.publisher.InnerOperator.currentContext(InnerOperator.java:32)
	at reactor.core.publisher.InnerOperator.currentContext(InnerOperator.java:32)
	at reactor.core.publisher.FluxFlatMap$FlatMapInner.cancel(FluxFlatMap.java:1036)
	at reactor.core.publisher.FluxFlatMap$FlatMapMain.unsubscribeEntry(FluxFlatMap.java:332)
	at reactor.core.publisher.FluxFlatMap$FlatMapMain.unsubscribeEntry(FluxFlatMap.java:212)
	at reactor.core.publisher.FlatMapTracker.unsubscribe(FluxFlatMap.java:1095)
	at reactor.core.publisher.FluxFlatMap$FlatMapMain.checkTerminated(FluxFlatMap.java:803)
	at reactor.core.publisher.FluxFlatMap$FlatMapMain.drainLoop(FluxFlatMap.java:600)
	at reactor.core.publisher.FluxFlatMap$FlatMapMain.tryEmit(FluxFlatMap.java:561)
	at reactor.core.publisher.FluxFlatMap$FlatMapInner.onNext(FluxFlatMap.java:999)
	at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:114)
	at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:192)
	at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1755)
	at reactor.core.publisher.MonoProcessor.onNext(MonoProcessor.java:317)
	at dev.miku.r2dbc.mysql.MySqlResult.lambda$null$3(MySqlResult.java:114)
	at reactor.core.publisher.LambdaSubscriber.onNext(LambdaSubscriber.java:160)
	at reactor.core.publisher.FluxWindowPredicate$WindowFlux.drainRegular(FluxWindowPredicate.java:650)
	at reactor.core.publisher.FluxWindowPredicate$WindowFlux.drain(FluxWindowPredicate.java:728)
	at reactor.core.publisher.FluxWindowPredicate$WindowFlux.onNext(FluxWindowPredicate.java:770)
	at reactor.core.publisher.FluxWindowPredicate$WindowPredicateMain.onNext(FluxWindowPredicate.java:228)
	at reactor.core.publisher.FluxHandleFuseable$HandleFuseableSubscriber.onNext(FluxHandleFuseable.java:178)
	at reactor.core.publisher.FluxContextStart$ContextStartSubscriber.onNext(FluxContextStart.java:96)
	at dev.miku.r2dbc.mysql.util.DiscardOnCancelSubscriber.onNext(DiscardOnCancelSubscriber.java:70)
	at reactor.core.publisher.FluxPeekFuseable$PeekConditionalSubscriber.onNext(FluxPeekFuseable.java:845)
	at reactor.core.publisher.MonoFlatMapMany$FlatMapManyInner.onNext(MonoFlatMapMany.java:242)
	at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:192)
	at reactor.core.publisher.FluxHandle$HandleSubscriber.onNext(FluxHandle.java:112)
	at reactor.core.publisher.FluxPeekFuseable$PeekConditionalSubscriber.onNext(FluxPeekFuseable.java:845)
	at reactor.core.publisher.EmitterProcessor.drain(EmitterProcessor.java:426)
	at reactor.core.publisher.EmitterProcessor.onNext(EmitterProcessor.java:268)
	at dev.miku.r2dbc.mysql.client.ReactorNettyClient$ResponseSink.next(ReactorNettyClient.java:340)
	at dev.miku.r2dbc.mysql.client.ReactorNettyClient.lambda$new$0(ReactorNettyClient.java:103)
	at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:177)
	at reactor.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:220)
	at reactor.netty.channel.FluxReceive.onInboundNext(FluxReceive.java:354)
	at reactor.netty.channel.ChannelOperations.onInboundNext(ChannelOperations.java:352)
	at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:96)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at dev.miku.r2dbc.mysql.client.MessageDuplexCodec.handleDecoded(MessageDuplexCodec.java:187)
	at dev.miku.r2dbc.mysql.client.MessageDuplexCodec.channelRead(MessageDuplexCodec.java:95)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324)
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.lang.Thread.run(Thread.java:748)
  • 并发量越大,复现的几率就越大。
  • 我将请求链路上的一次写数据库的操作注解后就没有复现这种情况。

相关问题