Open liuanxu opened 3 weeks ago
可以看下NPE的调用栈,一般是不恰当处理异步流程上下文设置导致的问题。 在异步回调中取上下文可能导致NPE,业务设计的时候需要理解下上下文传递的机制。
调用栈如下: 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)
这个问题需要业务自行分析下线程切换情况,看看这种异步线程切换的场景你们这样使用是否合理。混合使用异步,又使用ThreadLocal获取上下文(即InvocationContext, ThreadLocal一般用于在同一个线程里面传递数据,异步线程切换使用会有风险),很容易出现这种错误。
1、当前线程A服务代码中第73行使用RPC方式异步调用B服务:
2、负载均衡没有找到B服务可用的地址:
3、A服务当前线程上下文被清除:
4、A服务当前线程再接着调用C服务时,从上下文中获取参数时报空指针: