本文作者:suxingrui
本文链接:https://blog.csdn.net/suxingrui/article/details/103791284
版权声明:本文为原创文章,转载请注明出处。
回顾2019年碰到的问题及解决方式
问题:Nacos:实现版本控制调度,灰度版本隔离
问题发现:
版本上到正式环境之后,有一段灰度测试的时间。
这段时间老服务与新服务共存,不想老服务调用新服务,新服务可以调用老服务,
或者实现新老服务不能相互调度,所以需要做一定的版本隔离,
当灰度测试验证通过之后,再放开限制或者下线老服务。
然后查找官方文档跟源码,官方似乎不支持?或者我没找对地方
找不到,那只能自己实现
调查分析:
分析源码之后,得出Nacos的负载均衡是基于Ribbon的
ServerList也是在不存在Bean时,才会使用自定义的
所以顾名思义,直接改造NacosServerList就能够实现自己的目标
主要是改写NacosServerList的instancesToServerList方法,原有的逻辑比较简单:
解决方法:
1、我这里简单的改成版本匹配才调用,正常来说每个服务的版本不可能一致,需要根据实际情况调整,比如版本后再加上特定的字符串gray等
在原有的基础上添加按版本过滤的功能,如何设置版本等信息,请参照另外一篇博文:Nacos:展示服务列表中的服务的启动时间
/**
* @author xiaojing
* @author renhaojun
*/
@Slf4j
public class NacosServerList extends AbstractServerList<NacosServer> {
private NacosDiscoveryProperties discoveryProperties;
private String serviceId;
public NacosServerList(NacosDiscoveryProperties discoveryProperties) {
this.discoveryProperties = discoveryProperties;
}
@Override
public List<NacosServer> getInitialListOfServers() {
return getServers();
}
@Override
public List<NacosServer> getUpdatedListOfServers() {
return getServers();
}
private List<NacosServer> getServers() {
try {
List<Instance> instances = discoveryProperties.namingServiceInstance().selectInstances(serviceId, true);
return instancesToServerList(instances);
} catch (Exception e) {
throw new IllegalStateException("Can not get service instances from nacos, serviceId=" + serviceId, e);
}
}
private List<NacosServer> instancesToServerList(List<Instance> instances) {
List<NacosServer> result = new ArrayList<>();
if (CollectionUtils.isEmpty(instances)) {
return result;
}
boolean filter = false;
String curVer = discoveryProperties.getMetadata().get("version");
for (Instance instance : instances) {
// 按版本隔离服务
Map<String, String> tarMetadata = instance.getMetadata();
String tarVer = tarMetadata.get("version");
boolean tarSupportAll = "all".equalsIgnoreCase(tarMetadata.get("support"));
if (tarSupportAll || StringUtils.equals(curVer, tarVer)) {
result.add(new NacosServer(instance));
} else {
filter = true;
}
}
if (filter && result.size() == 0) {
log.info("{} 全部被过滤:{}", serviceId, instances);
}
return result;
}
public String getServiceId() {
return serviceId;
}
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
this.serviceId = iClientConfig.getClientName();
}
}
2、使用修改后的NacosServerList
/**
* 自定义Ribbon的策略
*
* @author suxingrui
* @time Aug 2, 2019 11:39:34 AM
*/
@Configuration
public class NacosRibbonConfiguration {
@Bean
public ServerList<?> ribbonServerList(IClientConfig config, NacosDiscoveryProperties nacosDiscoveryProperties) {
NacosServerList serverList = new NacosServerList(nacosDiscoveryProperties);
serverList.initWithNiwsConfig(config);
return serverList;
}
}
启动类加上注解:
@RibbonClients(defaultConfiguration = NacosRibbonConfiguration.class)