这里写自定义目录标题

问题描述

使用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);
    }
}
Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐