Nacos领域模型及负载均衡调用策略

Nacos领域模型及负载均衡调用策略

每天多学一点点~
话不多说,这就开始吧…

文章目录

  • Nacos领域模型及负载均衡调用策略
  • 1.前言
  • 2.Nacos领域模型划分
  • 3.同集群优先调用策略
  • 4.金丝雀版本权重负载均衡策略
  • 5.结语

1.前言

阿里,阿里爸爸,阿里爸爸开源的框架真的很精髓~

2.Nacos领域模型划分

Nacos领域模型及负载均衡调用策略_第1张图片

  • NameSpace:命名空间,默认的NameSpace是public。比如,我们开发,测试环境共用一个nacos,必定我们的接口地址也是不同,而且你在开发过程中,也是不建议随意配置测试环境的,这时我们就应该用namespace来隔离我们的空间。
    Nacos领域模型及负载均衡调用策略_第2张图片

  • group:分组。也是用来隔离的,打个比方啊,加入我们的用户服务,订单服务,仓储服务和物流服务四个服务,订单服务中有一个接口叫getData,仓储服务中也有一个接口叫getData,我们的用户服务只想调用到我们的订单服务的getData,不想调用到仓储服务的getData,这时我们可以用group分组来隔离。
    Nacos领域模型及负载均衡调用策略_第3张图片

  • cluster:集群。打个比方,我们现在有两组集群,一组是北京的订单服务集群,北京的商品服务集群,还有一组是南京的订单服务集群,南京的商品服务集群。 我们希望北京的订单集群,优先去调用北京的商品系统,南京的优先调用南京的集群服务。并不希望我们跨地区远程调用(如果组内实在没有服务了,也可以调用,但是优先考虑同一集群的)
    Nacos领域模型及负载均衡调用策略_第4张图片

  • metadata: 只要用于版本控制。比如,我们在开发中可能是多个版本共存的,订单的v1版本只能调商品的v1版本,订单的v2版本只能调商品的v2版本。
    Nacos领域模型及负载均衡调用策略_第5张图片

nacos官方文档

yml配置

spring:
  application:
    name: test-demo
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        namespace: 0610f97e-c25d-4f49-bfb8-b340e3584b82
        group: test
        cluster-name: BJ-cluster
        metadata:
          current-version: V1
server:
  port: 8888

3.同集群优先调用策略

@Slf4j
public class TheSameClusterPriorityRule extends AbstractLoadBalancerRule {

    @Autowired
    private NacosDiscoveryProperties discoveryProperties;

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {

    }

    @Override
    public Server choose(Object key) {
        try {
            //第一步:获取当前服务所在的集群
            String currentClusterName = discoveryProperties.getClusterName();

            //第二步:获取一个负载均衡对象
            BaseLoadBalancer baseLoadBalancer = (BaseLoadBalancer) getLoadBalancer();

            //第三步:获取当前调用的微服务的名称
            String invokedSerivceName = baseLoadBalancer.getName();

            //第四步:获取nacos clinet的服务注册发现组件的api
            NamingService namingService = discoveryProperties.namingServiceInstance();

            //第五步:获取所有的服务实例 包括不同集群的
            List<Instance> allInstance =  namingService.getAllInstances(invokedSerivceName);

            List<Instance> theSameClusterNameInstList = new ArrayList<>();

            //第六步:过滤筛选同集群下的所有实例
            for(Instance instance : allInstance) {
                if(StringUtils.endsWithIgnoreCase(instance.getClusterName(),currentClusterName)) {
                    theSameClusterNameInstList.add(instance);
                }
            }

            Instance toBeChooseInstance ;

            //第七步:选择合适的一个实例调用
            if(theSameClusterNameInstList.isEmpty()) {

                toBeChooseInstance = TulingWeightedBalancer.chooseInstanceByRandomWeight(allInstance);  //allInstance 所有实例(包括不同集群的)

                log.info("发生跨集群调用--->当前微服务所在集群:{},被调用微服务所在集群:{},Host:{},Port:{}",
                        currentClusterName,toBeChooseInstance.getClusterName(),toBeChooseInstance.getIp(),toBeChooseInstance.getPort());
            }else {
                toBeChooseInstance = TulingWeightedBalancer.chooseInstanceByRandomWeight(theSameClusterNameInstList);// theSameClusterNameInstList 通过集群实例

                log.info("同集群调用--->当前微服务所在集群:{},被调用微服务所在集群:{},Host:{},Port:{}",
                        currentClusterName,toBeChooseInstance.getClusterName(),toBeChooseInstance.getIp(),toBeChooseInstance.getPort());
            }

            return new NacosServer(toBeChooseInstance);

        } catch (NacosException e) {
            log.error("同集群优先权重负载均衡算法选择异常:{}",e);
        }
        return null;
    }
}

yml ribbon的 细粒度配置

product-center: # 需要配置的微服务名称
  ribbon:
    NFLoadBalancerRuleClassName: com.demo.myrule.TheSameClusterPriorityWithVersionRule  

4.金丝雀版本权重负载均衡策略

金丝雀版本发布,即灰度发布,同版本同集群优先调用

@Slf4j
public class TheSameClusterPriorityWithVersionRule extends AbstractLoadBalancerRule {

    @Autowired
    private NacosDiscoveryProperties discoveryProperties;

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {

    }

    @Override
    public Server choose(Object key) {

        try {

            String currentClusterName = discoveryProperties.getClusterName();

            List<Instance> theSameClusterNameAndTheSameVersionInstList = getTheSameClusterAndTheSameVersionInstances(discoveryProperties);

            //声明被调用的实例
            Instance toBeChooseInstance;

            //判断同集群同版本号的微服务实例是否为空
            if(theSameClusterNameAndTheSameVersionInstList.isEmpty()) {
                //跨集群调用相同的版本
                toBeChooseInstance = crossClusterAndTheSameVersionInovke(discoveryProperties);
            }else {
                // theSameClusterNameAndTheSameVersionInstList 同集群同版本的实例
                toBeChooseInstance = TulingWeightedBalancer.chooseInstanceByRandomWeight(theSameClusterNameAndTheSameVersionInstList);
                log.info("同集群同版本调用--->当前微服务所在集群:{},被调用微服务所在集群:{},当前微服务的版本:{},被调用微服务版本:{},Host:{},Port:{}",
                        currentClusterName,toBeChooseInstance.getClusterName(),discoveryProperties.getMetadata().get("current-version"),
                        toBeChooseInstance.getMetadata().get("current-version"),toBeChooseInstance.getIp(),toBeChooseInstance.getPort());
            }

            return new NacosServer(toBeChooseInstance);

        } catch (NacosException e) {
            log.error("同集群优先权重负载均衡算法选择异常:{}",e);
            return null;
        }
    }



    /**
     * 方法实现说明:获取相同集群下,相同版本的 所有实例
     * @author:smlz
     * @param discoveryProperties nacos的配置
     * @return: List
     */
    private List<Instance> getTheSameClusterAndTheSameVersionInstances(NacosDiscoveryProperties discoveryProperties) throws NacosException {

        //当前的集群的名称
        String currentClusterName = discoveryProperties.getClusterName();

        String currentVersion = discoveryProperties.getMetadata().get("current-version");// current-version 是配置在yml中的metadata下的

        //获取所有实例的信息(包括不同集群的)
        List<Instance> allInstance =  getAllInstances(discoveryProperties);

        List<Instance> theSameClusterNameAndTheSameVersionInstList = new ArrayList<>();

        //过滤相同集群的
        for(Instance instance : allInstance) {
            if(StringUtils.endsWithIgnoreCase(instance.getClusterName(),currentClusterName)&&
               StringUtils.endsWithIgnoreCase(instance.getMetadata().get("current-version"),currentVersion)) {

                theSameClusterNameAndTheSameVersionInstList.add(instance);
            }
        }

        return theSameClusterNameAndTheSameVersionInstList;
    }

    /**
     * 方法实现说明:获取被调用服务的所有实例
     * @author:smlz
     * @param discoveryProperties nacos的配置
     * @return: List
     */
    private List<Instance> getAllInstances(NacosDiscoveryProperties discoveryProperties) throws NacosException {

        //第1步:获取一个负载均衡对象
        BaseLoadBalancer baseLoadBalancer = (BaseLoadBalancer) getLoadBalancer();

        //第2步:获取当前调用的微服务的名称
        String invokedSerivceName = baseLoadBalancer.getName();

        //第3步:获取nacos clinet的服务注册发现组件的api
        NamingService namingService = discoveryProperties.namingServiceInstance();

        //第4步:获取所有的服务实例
        List<Instance> allInstance =  namingService.getAllInstances(invokedSerivceName);

        return allInstance;
    }

    private Instance crossClusterAndTheSameVersionInovke(NacosDiscoveryProperties discoveryProperties) throws NacosException {

        //获取所有集群下相同版本的实例信息
        List<Instance>  crossClusterAndTheSameVersionInstList = getCrossClusterAndTheSameVersionInstList(discoveryProperties);
        //当前微服务的版本号
        String currentVersion = discoveryProperties.getMetadata().get("current-version");
        //当前微服务的集群名称
        String currentClusterName = discoveryProperties.getClusterName();

        //声明被调用的实例
        Instance toBeChooseInstance = null ;

        //没有对应相同版本的实例
        if(crossClusterAndTheSameVersionInstList.isEmpty()) {
            log.info("跨集群调用找不到对应合适的版本当前版本为:currentVersion:{}",currentVersion);
            throw new RuntimeException("找不到相同版本的微服务实例");
        }else {
            //crossClusterAndTheSameVersionInstList 所有的,同版本不同集群
            toBeChooseInstance = TulingWeightedBalancer.chooseInstanceByRandomWeight(crossClusterAndTheSameVersionInstList);

            log.info("跨集群同版本调用--->当前微服务所在集群:{},被调用微服务所在集群:{},当前微服务的版本:{},被调用微服务版本:{},Host:{},Port:{}",
                    currentClusterName,toBeChooseInstance.getClusterName(),discoveryProperties.getMetadata().get("current-version"),
                    toBeChooseInstance.getMetadata().get("current-version"),toBeChooseInstance.getIp(),toBeChooseInstance.getPort());
        }

        return toBeChooseInstance;
    }

    /**
     * 方法实现说明:跨集群环境下 相同版本的
     * @author:smlz
     * @param discoveryProperties
     * @return: List
     */
    private List<Instance> getCrossClusterAndTheSameVersionInstList(NacosDiscoveryProperties discoveryProperties) throws NacosException {

        //版本号
        String currentVersion = discoveryProperties.getMetadata().get("current-version");

        //被调用的所有实例
        List<Instance> allInstance = getAllInstances(discoveryProperties);

        List<Instance>  crossClusterAndTheSameVersionInstList = new ArrayList<>();

        //过滤相同版本
        for(Instance instance : allInstance) {
            if(StringUtils.endsWithIgnoreCase(instance.getMetadata().get("current-version"),currentVersion)) {

                crossClusterAndTheSameVersionInstList.add(instance);
            }
        }

        return crossClusterAndTheSameVersionInstList;
    }
}

yml ribbon的 细粒度配置

order-center: # 需要配置的微服务名称
  ribbon:
    NFLoadBalancerRuleClassName: com.demo.myrule.TheSameClusterPriorityWithVersionRule

5.结语

世上无难事,只怕有心人,每天积累一点点,fighting!!!

你可能感兴趣的:(Nacos领域模型及负载均衡调用策略)