利用nacos元数据,给服务发起方和被调用方定义标签。相同标签的优先调用。
假设 A,B两个服务,各存在4个节点,且版本都是V1
A1(V1) B1(V1)
A2(V1) B2(V1)
A3(V1) B3(V1)
A4(V1) B4(V1)
更新版本后
A1(V2) B1(V2)
A2(V1) B2(V1)
A3(V1) B3(V1)
A4(V1) B4(V1)
更新后V2的相互调用,V1的相互调用。
参考NacosRule类 ,更复杂的情况可以依例扩展

pom.xml
- <dependencies>
- <dependency>
- <groupId>com.alibaba.cloudgroupId>
- <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
- dependency>
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-configuration-processorartifactId>
- <optional>trueoptional>
- dependency>
- <dependency>
- <groupId>org.projectlombokgroupId>
- <artifactId>lombokartifactId>
- dependency>
- dependencies>
GrayConstant.java
- package com.rutron.canary;
-
- /**
- * @author liwenchao
- */
- public class GrayConstant {
-
- public static final String GRAY_TAG = "version";
-
- }
CanaryBalancerRule.java
- package com.rutron.canary;
-
- import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
- import com.alibaba.cloud.nacos.NacosServiceManager;
- import com.alibaba.cloud.nacos.ribbon.ExtendBalancer;
- import com.alibaba.cloud.nacos.ribbon.NacosServer;
- import com.alibaba.nacos.api.naming.NamingService;
- import com.alibaba.nacos.api.naming.pojo.Instance;
- import com.netflix.client.config.IClientConfig;
- import com.netflix.loadbalancer.AbstractLoadBalancerRule;
- import com.netflix.loadbalancer.DynamicServerListLoadBalancer;
- import com.netflix.loadbalancer.Server;
- import lombok.extern.slf4j.Slf4j;
- import org.apache.commons.lang3.StringUtils;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.util.CollectionUtils;
-
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Map;
-
- /**
- * @author liwenchao
- */
- @Slf4j
- public class CanaryBalancerRule extends AbstractLoadBalancerRule {
-
- @Autowired
- private NacosDiscoveryProperties nacosDiscoveryProperties;
-
- @Autowired
- private NacosServiceManager nacosServiceManager;
-
- public CanaryBalancerRule() {
-
- }
-
- @Override
- public void initWithNiwsConfig(IClientConfig iClientConfig) {
-
- }
-
- @Override
- public Server choose(Object key) {
- try {
- String clusterName = this.nacosDiscoveryProperties.getClusterName();
- String group = this.nacosDiscoveryProperties.getGroup();
- Map
ribbonAttributes = this.nacosDiscoveryProperties.getMetadata(); - DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer();
- String serviceName = loadBalancer.getName();
- NamingService namingService = this.nacosServiceManager.getNamingService(this.nacosDiscoveryProperties.getNacosProperties());
- List
allInstances = namingService.selectInstances(serviceName, group, true); - List
grayInstances = new ArrayList<>(); - List
noneGrayInstances = new ArrayList<>(); - Instance toBeChooseInstance;
- if (CollectionUtils.isEmpty(allInstances)) {
- log.warn("no instance in service {}", serviceName);
- return null;
- } else {
- if (StringUtils.isNotBlank(clusterName)) {
- for (Instance instance : allInstances) {
- Map
metadata = instance.getMetadata(); - //当前服务的灰度标签和被调用的服务的灰度标签比,相同则灰色
- if (!ribbonAttributes.containsKey(GrayConstant.GRAY_TAG) || !metadata.containsKey(GrayConstant.GRAY_TAG)) {
- noneGrayInstances.add(instance);
- } else if (ribbonAttributes.get(GrayConstant.GRAY_TAG).trim().equalsIgnoreCase(metadata.get(GrayConstant.GRAY_TAG).trim())) {
- grayInstances.add(instance);
- } else if (!StringUtils.isBlank(metadata.get(GrayConstant.GRAY_TAG))) {
- noneGrayInstances.add(instance);
- }
- }
- }
- if (grayInstances.size() > 0) {
- toBeChooseInstance = ExtendBalancer.getHostByRandomWeight2(grayInstances);
- return new NacosServer(toBeChooseInstance);
- }
- if (noneGrayInstances.size() > 0) {
- toBeChooseInstance = ExtendBalancer.getHostByRandomWeight2(noneGrayInstances);
- } else {
- toBeChooseInstance = ExtendBalancer.getHostByRandomWeight2(allInstances);
- }
- return new NacosServer(toBeChooseInstance);
- }
- } catch (Exception e) {
- log.warn("NacosRule error", e);
- return null;
- }
- }
- }
RibbonAutoConfiguration.java
- package com.rutron.canary;
-
- import com.netflix.loadbalancer.IRule;
- import org.springframework.context.annotation.Bean;
-
- /**
- * @author liwenchao
- */
- public class RibbonAutoConfiguration {
-
- /**
- * 全局配置指定负载均衡策略
- */
- @Bean
- public IRule canaryBalancerRule() {
- return new CanaryBalancerRule();
- }
- }
spring.factories
- org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
- com.rutron.canary.RibbonAutoConfiguration

调用者和被调用者添加元数据
{
"preserved.register.source": "SPRING_CLOUD",
"version":"v2"
}