sofastack / sofa-rpc

SOFARPC is a high-performance, high-extensibility, production-level Java RPC framework.
https://www.sofastack.tech/sofa-rpc/docs/Home
Apache License 2.0
3.81k stars 1.16k forks source link

Nacos+SofaRpc 更新订阅端监听器 并发疑问 #1380

Closed symon-lin closed 3 months ago

symon-lin commented 6 months ago

Your question

                if (providerObserver == null) {
                    providerObserver = new NacosRegistryProviderObserver();
                }

                ProviderInfoListener providerInfoListener = config.getProviderInfoListener();
                providerObserver.addProviderListener(config, providerInfoListener);

                EventListener eventListener = new EventListener() {
                    @Override
                    public void onEvent(Event event) {
                        if (event instanceof NamingEvent) {
                            NamingEvent namingEvent = (NamingEvent) event;
                            List<Instance> instances = namingEvent.getInstances();
                            // avoid npe
                            if (null == instances) {
                                instances = new ArrayList<Instance>();
                            }
                            providerObserver.updateProviders(config, instances);
                        }
                    }
                };
                namingService.subscribe(serviceName, defaultCluster, eventListener);
                consumerListeners.put(config, eventListener);

上面的代码中,providerObserver = new NacosRegistryProviderObserver(); 没有对providerObserver进行加锁控制,是否会出现并发的情况下(比如:多模块并行启动),存在多个服务订阅端,然后前面的一个Consumer创建了Observer类,然后后面的Consumer也创建了Observer类并进行覆盖,导致前面的Consumer listener丢失的情况。

Environment

nobodyiam commented 6 months ago

粗看了下,是会有这个隐患

symon-lin commented 6 months ago

如何解决呢?升级版本?

EvenLjj commented 5 months ago

@symon-lin 这应该是个 bug,当多个 Consumer 共用一个 NacosRegistry 实例时会发生。一种解决方案是 providerObserver 的初始化可以放到 init 方法中去。后续会去修复这个问题,如果感兴趣的话,可以参与贡献。如果你自己的生产代码需要立马修复,可以写个nacos 的 Extension 去覆盖 sofarpc 的实现。