后台服务重启导致服务调用方获取nacos服务列表过时调用报错

这里写自定义目录标题

问题描述

使用springcloudgateway做网关,服务注册到nacos上,当后台服务重启后,由于服务是部署在k8s上,重启后IP和端口改变,nacos本地缓存列表是35秒后更新,导致服务调用报错

前提

使用nacos默认ribbon作为负载均衡,使用loadbalancer无效

解决

springcloud提供了ServerListUpdater接口让用户自定义实现本地服务列表更新策略,
只需实现接口并注入到spring容器即可

public class NacosServerListUpdater extends PollingServerListUpdater {

  private static final Logger log = LoggerFactory.getLogger(NacosWatch.class);


  private Map<String, EventListener> listenerMap = new ConcurrentHashMap<>(16);

  private NacosServiceManager nacosServiceManager;

  private NacosDiscoveryProperties properties;
  
  public NacosServerListUpdater(NacosServiceManager nacosServiceManager, NacosDiscoveryProperties properties){
    this.nacosServiceManager = nacosServiceManager;
    this.properties = properties;
  }

  @Override
  public synchronized void start(UpdateAction updateAction) {
    EventListener eventListener = listenerMap.computeIfAbsent(getClientName(updateAction),
        event -> new EventListener() {
          @Override
          public void onEvent(Event event) {
            if (event instanceof NamingEvent) {
              updateAction.doUpdate();
            }
          }
        });
    NamingService namingService = nacosServiceManager
        .getNamingService(properties.getNacosProperties());
    try {
      namingService.subscribe(getClientName(updateAction), eventListener);
    } catch (Exception e) {
      log.error("namingService subscribe failed, properties:{}", properties, e);
    }
  }

  @Override
  public synchronized void stop() {
    listenerMap.forEach((service, listener) -> {
      NamingService namingService = nacosServiceManager
          .getNamingService(properties.getNacosProperties());
      try {
        namingService.unsubscribe(service, listener);
      } catch (NacosException e) {
        log.error("namingService unsubscribe failed, properties:{}", properties, e);
      }
    });
  }

  /**
   * 通过updateAction获取服务名,这种方法比较粗暴
   *
   * @param updateAction
   * @return
   */
  private String getClientName(UpdateAction updateAction) {
    try {
      Class<?> bc = updateAction.getClass();
      Field field = bc.getDeclaredField("this$0");
      field.setAccessible(true);
      BaseLoadBalancer baseLoadBalancer = (BaseLoadBalancer) field.get(updateAction);
      return baseLoadBalancer.getClientConfig().getClientName();
    } catch (Exception e) {
      e.printStackTrace();
      throw new IllegalStateException(e);
    }
  }
}
@Configuration
@ConditionalOnRibbonNacos
public class RibbonConfig {
    @Bean
    public ServerListUpdater ribbonServerListUpdater(NacosServiceManager nacosServiceManager, NacosDiscoveryProperties properties) {
        return new NacosServerListUpdater(nacosServiceManager, properties);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值