spring-cloud-alibaba icon indicating copy to clipboard operation
spring-cloud-alibaba copied to clipboard

是否提供ribbon基于事件机制的ServerListUpdater

Open joyuce opened this issue 4 years ago • 9 comments

使用feign调用服务时,ribbon默认使用PollingServerListUpdater定时任务更新服务,eureka有对应的EurekaNotificationServerListUpdater基于事件的更新,目前nacos是否有提供对应的基于事件的ServerListUpdater,可以更快的感知到服务的上下线。

joyuce avatar Jun 30 '20 02:06 joyuce

welcome to contribute it!

fangjian0423 avatar Jul 22 '20 06:07 fangjian0423

这个功能确实很急需啊

RainElohim avatar Aug 12 '20 09:08 RainElohim

is there any progress?

phantomedc avatar Jan 25 '21 08:01 phantomedc

如果仅仅基于Ribbon,可以自行扩展,可以参考https://gitee.com/nepxion/Discovery/blob/6.x.x/discovery-plugin-register-center/discovery-plugin-register-center-starter-nacos/src/main/java/com/nepxion/discovery/plugin/registercenter/nacos/decorator/NacosServerListDecorator.java

getUpdatedListOfServers上触发出一个事件即可,仅供参考

HaojunRen avatar Jan 25 '21 09:01 HaojunRen

最终我基于namingService subscribe API重写了ServerListUpdater接口,基本实现基于事件机制的ServerListUpdater,但是在实测中发现,nacos的事件推送很不稳定,在服务节点下线后基本需要5-10秒以后client才能收到NamingEvent,作为事件订阅本身来讲,这个延迟是否可以接受?是否还有优化空间?


顺着eventListener的源码往上扒了扒,发现Nacos的事件订阅实际上是基于pull模式的“伪订阅”…,然后去阿里云看了一下MSE的服务下线优势…大概明白为啥Eureka有基于事件监听机制的ServerListUpdater而Nacos没有了…

phantomedc avatar Jan 27 '21 08:01 phantomedc

最终我基于namingService subscribe API重写了ServerListUpdater接口,基本实现基于事件机制的ServerListUpdater,但是在实测中发现,nacos的事件推送很不稳定,在服务节点下线后基本需要5-10秒以后client才能收到NamingEvent,作为事件订阅本身来讲,这个延迟是否可以接受?是否还有优化空间?

顺着eventListener的源码往上扒了扒,发现Nacos的事件订阅实际上是基于pull模式的“伪订阅”…,然后去阿里云看了一下MSE的服务下线优势…大概明白为啥Eureka有基于事件监听机制的ServerListUpdater而Nacos没有了…

您好,可以麻烦您提供下基于事件机制的ServerListUpdater的源码吗?谢谢。

woshishitou avatar Apr 13 '21 06:04 woshishitou

监听器实现参考

/**
 * @author: ruansheng
 * @date: 2022-08-08
 */
@RequiredArgsConstructor
public class NacosInstancesChangeNotifier extends Subscriber<InstancesChangeEvent> implements SmartInitializingSingleton {

    private final SpringClientFactory springClientFactory;
    private final String applicationName;

    @Override

    public void onEvent(InstancesChangeEvent event) {
        ILoadBalancer loadBalancer = this.springClientFactory.getLoadBalancer(event.getServiceName());
        if (this.applicationName.equals(event.getServiceName()) || !(loadBalancer instanceof DynamicServerListLoadBalancer)) {
            return;
        }
        ((DynamicServerListLoadBalancer<?>) loadBalancer).updateListOfServers();
    }

    @Override
    public Class<? extends Event> subscribeType() {
        return InstancesChangeEvent.class;
    }

    @Override
    public void afterSingletonsInstantiated() {
        NotifyCenter.registerSubscriber(this);
    }
}

定义监听器

    @Bean
    public NacosInstancesChangeNotifier nacosInstancesChangeNotifier(SpringClientFactory springClientFactory, Environment environment) {
        String applicationName = environment.getProperty("spring.application.name", "");
        return new NacosInstancesChangeNotifier(springClientFactory, applicationName);
    }

ruansheng8 avatar Aug 08 '22 10:08 ruansheng8

监听器实现参考

/**
 * @author: ruansheng
 * @date: 2022-08-08
 */
@RequiredArgsConstructor
public class NacosInstancesChangeNotifier extends Subscriber<InstancesChangeEvent> implements SmartInitializingSingleton {

    private final SpringClientFactory springClientFactory;
    private final String applicationName;

    @Override

    public void onEvent(InstancesChangeEvent event) {
        ILoadBalancer loadBalancer = this.springClientFactory.getLoadBalancer(event.getServiceName());
        if (this.applicationName.equals(event.getServiceName()) || !(loadBalancer instanceof DynamicServerListLoadBalancer)) {
            return;
        }
        ((DynamicServerListLoadBalancer<?>) loadBalancer).updateListOfServers();
    }

    @Override
    public Class<? extends Event> subscribeType() {
        return InstancesChangeEvent.class;
    }

    @Override
    public void afterSingletonsInstantiated() {
        NotifyCenter.registerSubscriber(this);
    }
}

定义监听器

    @Bean
    public NacosInstancesChangeNotifier nacosInstancesChangeNotifier(SpringClientFactory springClientFactory, Environment environment) {
        String applicationName = environment.getProperty("spring.application.name", "");
        return new NacosInstancesChangeNotifier(springClientFactory, applicationName);
    }

nacos的事件推送是不稳定的, 所以这样也不能很好的解决

zhaoxilingcheng avatar Mar 29 '24 02:03 zhaoxilingcheng

@zhaoxilingcheng 长期的使用验证下来,nacos 的推送事件稳定性还是很高的。

当然,还可以同时配合其他机制来进一步保证稳定性,例如:当前服务实例下线时,基于消息订阅等相关方式将当前下线的实例通知给其他服务,然后其他服务将“下线的服务实例”缓存到当前服务的“黑名单”中,然后在负载均衡选择实例的时候跳过“黑名单”中的实例即可。

ruansheng8 avatar Mar 29 '24 04:03 ruansheng8