后台服务重启导致服务调用方获取nacos服务列表过时调用报错
使用springcloudgateway做网关,服务注册到nacos上,当后台服务重启后,由于服务是部署在k8s上,重启后IP和端口改变,nacos本地缓存列表是35秒后更新,导致服务调用报错。springcloud提供了ServerListUpdater接口让用户自定义实现本地服务列表更新策略,使用nacos默认ribbon作为负载均衡,使用loadbalancer无效。只需实现接口并注入到sp
·
问题描述
使用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);
}
}
更多推荐
已为社区贡献1条内容
所有评论(0)