apache / servicecomb-java-chassis

ServiceComb Java Chassis is a Software Development Kit (SDK) for rapid development of microservices in Java, providing service registration, service discovery, dynamic routing, and service management features
Apache License 2.0
1.91k stars 813 forks source link

A服务RPC调用B服务找不到可用地址时,导致当前线程上下文被清除,接着再调用C服务时取CSE上下文报空指针异常 #4569

Open liuanxu opened 3 weeks ago

liuanxu commented 3 weeks ago

1、当前线程A服务代码中第73行使用RPC方式异步调用B服务: 业务逻辑调用

2、负载均衡没有找到B服务可用的地址: 负载均衡没有可用机器

3、A服务当前线程上下文被清除: 当前线程上下文被清除

4、A服务当前线程再接着调用C服务时,从上下文中获取参数时报空指针: 调B服务失败后再取上下文时报空指针异常

liubao68 commented 3 weeks ago

可以看下NPE的调用栈,一般是不恰当处理异步流程上下文设置导致的问题。 在异步回调中取上下文可能导致NPE,业务设计的时候需要理解下上下文传递的机制。

liuanxu commented 2 weeks ago

调用栈如下: 2024-10-22 15:10:19,464|ERROR|67174fdb5ba5c14c|multiListThreadPool-38|requestPlacement error:java.lang.NullPointerException\n at com.huawei.appgallery.header.model.CseHeader.getServiceZoneCode(CseHeader.java:153)\n at com.huawei.apppromote.apcns.domain.service.medium.MediumStrategyService.buildMediumStrategy(MediumStrategyService.java:100)\n at com.huawei.apppromote.apcns.domain.service.medium.MediumStrategyService.getMediumStrategyByReq(MediumStrategyService.java:86)\n at com.huawei.apppromote.apcns.domain.service.medium.MediumStrategyService.getMediumStrategy(MediumStrategyService.java:73)\n at com.huawei.apppromote.apcns.domain.service.dispatch.DispatcherPolicy.getMediumStrategyInfo(DispatcherPolicy.java:283)\n at com.huawei.apppromote.apcns.domain.service.dispatch.DispatcherPolicy.getStrategy(DispatcherPolicy.java:102)\n at com.huawei.apppromote.apcns.application.GetAdsPromoteServiceImp.requestPlacement(GetAdsPromoteServiceImp.java:94)\n at com.huawei.apppromote.apcns.application.GetAdsPromoteServiceImp.processReq(GetAdsPromoteServiceImp.java:77)\n at com.huawei.apppromote.apcns.application.GetAdsMultiListPromoteService.processReq(GetAdsMultiListPromoteService.java:63)\n at com.huawei.apppromote.apcns.application.GetAdsMultiListPromoteService.processReq(GetAdsMultiListPromoteService.java:34)\n at com.huawei.apppromote.apcns.application.AppPromoteServiceAbs.process(AppPromoteServiceAbs.java:110)\n at com.huawei.apppromote.apcns.interfaces.delegate.ConnectServiceApiDelegateImpl.getMultiListAds(ConnectServiceApiDelegateImpl.java:163)\n at com.huawei.appgallery.api.provider.ConnectServiceApiController.getMultiListAds(ConnectServiceApiController.java:110)\n at sun.reflect.GeneratedMethodAccessor1711.invoke(Unknown Source)\n at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n at java.lang.reflect.Method.invoke(Method.java:498)\n at org.apache.servicecomb.core.handler.impl.ProducerOperationHandler.doInvoke(ProducerOperationHandler.java:125)\n at org.apache.servicecomb.core.handler.impl.ProducerOperationHandler.syncInvoke(ProducerOperationHandler.java:110)\n at org.apache.servicecomb.core.handler.impl.ProducerOperationHandler.invoke(ProducerOperationHandler.java:63)\n at org.apache.servicecomb.core.handler.impl.ProducerOperationHandler.handle(ProducerOperationHandler.java:54)\n at org.apache.servicecomb.core.Invocation.next(Invocation.java:280)\n at com.huawei.olc.cse.plugin.OlcHandlerUtilBase.nextInvocation(OlcHandlerUtilBase.java:197)\n at com.huawei.olc.cse.plugin.OlcHandlerUtilBase.handle(OlcHandlerUtilBase.java:171)\n at com.huawei.olc.cse.plugin.ProviderGreatwallHandler.handle(ProviderGreatwallHandler.java:39)\n at org.apache.servicecomb.core.Invocation.next(Invocation.java:280)\n at com.huawei.apppromote.apcns.infrastructure.exception.ExceptionHandler.handle(ExceptionHandler.java:32)\n at org.apache.servicecomb.core.Invocation.next(Invocation.java:280)\n at org.apache.servicecomb.qps.ProviderQpsFlowControlHandler.handle(ProviderQpsFlowControlHandler.java:38)\n at org.apache.servicecomb.core.Invocation.next(Invocation.java:280)\n at org.apache.servicecomb.common.rest.AbstractRestInvocation.doInvoke(AbstractRestInvocation.java:295)\n at org.apache.servicecomb.common.rest.AbstractRestInvocation.invoke(AbstractRestInvocation.java:266)\n at org.apache.servicecomb.common.rest.AbstractRestInvocation.runOnExecutor(AbstractRestInvocation.java:250)\n at org.apache.servicecomb.common.rest.AbstractRestInvocation.lambda$scheduleInvocation$2(AbstractRestInvocation.java:206)\n at com.alibaba.ttl.TtlRunnable.run(TtlRunnable.java:60)\n at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\n at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\n at java.lang.Thread.run(Thread.java:750)\n|367371013df440c5b9f5d5d49d139f22|com.huawei.apppromote.apcns.application.GetAdsPromoteServiceImp.requestPlacement(GetAdsPromoteServiceImp.java:100)

liubao68 commented 1 week ago

这个问题需要业务自行分析下线程切换情况,看看这种异步线程切换的场景你们这样使用是否合理。混合使用异步,又使用ThreadLocal获取上下文(即InvocationContext, ThreadLocal一般用于在同一个线程里面传递数据,异步线程切换使用会有风险),很容易出现这种错误。