1.3 自定义ribbon负载均衡策略

摘要:
自定义Ribbon负载均衡一.按照权重实现负载均衡ribbon本身是没有权重的概念的,那么如何才能实现代用权重的负载均衡呢?

自定义Ribbon负载均衡

一. 按照权重实现负载均衡

ribbon本身是没有权重的概念的, 那么如何才能实现代用权重的负载均衡呢?

我们在nacos中, 服务其的集群有一个权重的概念, 当给服务器设置了权重, 那么流量就可以根据权重比例分配到服务器上.

1. 先来看看如何自定义一个负载均衡策略.

首先是继承自AbstractLoadBalancerRule. 从下面这张图可以看出, ribbon自定义的策略, 最终都继承自这个类, 这个类封装了负载均衡策略的公共方法.

1.3 自定义ribbon负载均衡策略第1张

在nacos中可以配置服务器的权重

在nacos中,有两个重要的类, 一个是NameService, 一个是ConfigService

  • NameService: 注册中心
  • ConfigService: 配置中心
二. 实现带有权重的负载均衡器

第一步: 自定义一个带有权重的负载均衡器MyWeightRule

1.3 自定义ribbon负载均衡策略第2张

package com.lxl.www.gateway.myrule;

import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.ribbon.NacosServer;
import com.alibaba.nacos.api.exception.NacosException;
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.BaseLoadBalancer;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * 自定义一个权重负载均衡策略
 */@Slf4j
public classMyWeightRule extends AbstractLoadBalancerRule {

    @Autowired
    privateNacosDiscoveryProperties discoveryProperties;

    @Override
    public voidinitWithNiwsConfig(IClientConfig iClientConfig) {
        //读取配置文件, 并且初始化, ribbon内部基本上用不上
}

    /**
     * 这个方法是实现负载均衡策略的方法
     *
     * @param
     * @return
     */@Override
    publicServer choose(Object key) {
        try{
            log.info("key:{}", key);
            //调用父类方法, 获取当前使用的负载均衡器
            BaseLoadBalancer baseLoadBalancer = (BaseLoadBalancer) this.getLoadBalancer();
            //获取当前服务的名称
            String serviceName =baseLoadBalancer.getName();

            /**
             * namingService: 获取nacos的服务发现API
             */NamingService namingService =discoveryProperties.namingServiceInstance();

            /**
             * 根据名称获取服务发现实例
             * 在selectOneHealthyInstance中, nacos实现了权重的负载均衡算法
             */Instance instance =namingService.selectOneHealthyInstance(serviceName);

            return newNacosServer(instance);
        } catch(NacosException e) {
            e.printStackTrace();
        }

        return null;
    }
}

第二步: 启用自定义的负载均衡器应用

修改自定义的ribbon config.

package com.lxl.www.gateway.config;

import com.lxl.www.ribbonconfig.GlobalRibbonConfig;
import org.springframework.cloud.netflix.ribbon.RibbonClients;
import org.springframework.context.annotation.Configuration;

@Configuration
/*@RibbonClients(value = {
        @RibbonClient(name="product", configuration = ProductConfiguration.class),
        @RibbonClient(name = "customer", configuration = CustomerConfiguration.class)
})*/
//使用全局的配置
@RibbonClients(defaultConfiguration = GlobalRibbonConfig.class)
public classCustomeRibbonConfig {

}

设置为全局配置GlobalRibbonConfig.class

然后在全局配置中,我们执行当前使用的负载均衡策略是自定义的权重负载均衡策略

package com.lxl.www.ribbonconfig;

import com.lxl.www.gateway.myrule.MyWeightRule;
import com.netflix.loadbalancer.IRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public classGlobalRibbonConfig {

    @Bean
    publicIRule getRule() {
        //实现带有权重的负载均衡策略
        return newMyWeightRule();
    }
}

第三步:启动服务, 并设置nacos权重

1.3 自定义ribbon负载均衡策略第3张

我们看到启动了两台product, 一台order. 接下来设置product两台实例的权重

1.3 自定义ribbon负载均衡策略第4张

我们看到一个设置为0.1, 另一个是0.9, 也就是说如果有10次请求, 基本上都是会打到8083端口上的.

第四步: 浏览器访问连接, 测试结果

http://localhost:8080/get/product

触发了10次请求, 基本上都打到了8083服务器上.

三 实现同集群优先调用原则的负载均衡器

尽量避免跨集群调用

比如, 南京集群的product优先调用南京集群的order . 北京集群的product优先调用北京集群的order.

1.3 自定义ribbon负载均衡策略第5张

实现如上图所示的功能

我们有product服务和order服务, 假设各有10台. product和order有5台部署在北京集群上, 另外5台部署在南京集群上.

那么当有请求打到南京的product的时候, 那么他调用order要优先调用南京集群的, 南京集群没有了, 在调用北京集群的.

当有请求打到北京的product的是偶, 优先调用北京集群的order, 北京没有找到, 再去调用南京的order.

第一步: 自定义一个同集群优先策略的负载均衡器

1.3 自定义ribbon负载均衡策略第6张

package com.lxl.www.gateway.myrule;

import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.ribbon.NacosServer;
import com.alibaba.nacos.api.exception.NacosException;
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.BaseLoadBalancer;
import com.netflix.loadbalancer.Server;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.omg.PortableInterceptor.INACTIVE;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * 同集群优先调用--负载均衡策略
 */@Slf4j
public classTheSameClusterPriorityRule extends AbstractLoadBalancerRule {

    @Autowired
    privateNacosDiscoveryProperties discoveryProperties;

    @Override
    public voidinitWithNiwsConfig(IClientConfig iClientConfig) {

    }

    /**
     * 主要实现choose方法
     *
     * @param o
     * @return
     */@Override
    publicServer choose(Object o) {
        try{
            //第一步: 获取服务所在的集群名称
            String clusterName =discoveryProperties.getClusterName();
            //第二步: 获取当前负载均衡器
            BaseLoadBalancer loadBalancer = (BaseLoadBalancer) this.getLoadBalancer();
            //第三步: 获取当前服务的实例名称
            String serviceName =loadBalancer.getName();
            //第四步: 获取nacos client服务注册发现api
            NamingService namingService =discoveryProperties.namingServiceInstance();
            //第五步: 通过namingService获取当前注册的所有服务实例
            List<Instance> allInstances =namingService.getAllInstances(serviceName);
            List<Instance> instanceList = new ArrayList<>();
            //第六步: 过滤筛选同集群下的服务实例
            for(Instance instance: allInstances) {
                if(StringUtils.endsWithIgnoreCase(instance.getClusterName(), clusterName)) {
                    instanceList.add(instance);
                }
            }
            Instance toBeChooseInstance;
            //第七步: 选择合适的服务实例
            if (instanceList == null || instanceList.size() == 0) {
                //从其他集群中随机选择一个服务实例
                toBeChooseInstance =WeightedBalancer.chooseInstanceByRandomWeight(allInstances);
                log.info("跨集群调用---{}", toBeChooseInstance.getPort());
            } else{
                //从本集群中随机选择一个服务实例
                toBeChooseInstance =WeightedBalancer.chooseInstanceByRandomWeight(instanceList);
                log.info("同集群调用---{}", toBeChooseInstance.getPort());
            }
            return newNacosServer(toBeChooseInstance);
        } catch(NacosException e) {
            e.printStackTrace();
        }
        return null;
    }
}

1.3 自定义ribbon负载均衡策略第7张

package com.lxl.www.gateway.myrule;

import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.client.naming.core.Balancer;

import java.util.List;

/**
 * 根据权重随机选择一个实例
 */
public classWeightedBalancer extends Balancer {
    public static Instance chooseInstanceByRandomWeight (List<Instance>instanceList) {
        returngetHostByRandomWeight(instanceList);
    }
}

第二步: 设置当前的负载均衡策略为同集群优先策略

@Configuration
/*@RibbonClients(value = {
        @RibbonClient(name="product", configuration = ProductConfiguration.class),
        @RibbonClient(name = "customer", configuration = CustomerConfiguration.class)
})*/
//使用全局的配置
@RibbonClients(defaultConfiguration = GlobalRibbonConfig.class)
public classCustomeRibbonConfig {

}
@Configuration
public classGlobalRibbonConfig {

    @Bean
    publicIRule getRule() {
        //实现带有权重的负载均衡策略
        //return new MyWeightRule();
        //实现同集群优先的服务实例
        return newTheSameClusterPriorityRule();
    }
}

第三步: 启动服务

1.3 自定义ribbon负载均衡策略第8张

可以看到order服务实例有1台, 所属集群是BJ-CLUSTER, product服务有4台. BJ-CLUSTER和NJ-CLUSTER各两台

1.3 自定义ribbon负载均衡策略第9张

第四步: 访问请求

http://localhost:8080/get/product

由于order服务是BJ-CLUSTER, 所以, 我们看到流量是随机打到了ORDER的BJ-CLUSTER集群上.

停止BJ-CLUSTER集群的两台实例, 现在BJ-CLUSTER集群上没有order的服务实例了, 这是在请求, 流量就会达到NJ-CLUSTER上.

四. 金丝雀发布--实现同版本同集群优先负载均衡策略

1.3 自定义ribbon负载均衡策略第10张

金丝雀发布, 也称为灰度发布, 是什么意思呢?

首先, 我们的product服务实例有100台, order服务实例有100台.现在都是在v1 版本上

然后新开发了一个变化很大的功能, 为了保证效果, 要进行灰度测试

在product-center上发布了5台, 在order-center上发布了5台

那么现在用户的流量过来了, 我们要设定一部分用户, 请求的是v1版本的流量, 而且全部都走v1版本, product-center, order-center都是v1版本

如果过来的用户, 请求的v2版本的流量, 那么product和order都走v2版本.

下面我们要实现的功能描述如下:

1.3 自定义ribbon负载均衡策略第11张

1. 同集群,同版本优先调用,

2. 没有同集群的服务提供者, 进行跨集群,同版本调用

3. 不可以进行不同版本间的调用

也就是说: 南京集群V1版本的product优先调用南京集群V1版本的order, 如果没有南京集群V1版本的order, 那么就调用北京集群V1版本的order, 那么能调用v2版本的么? 当然不行.

下面来具体实现一下

第一步: 实现带有版本的集群优先策略的负载均衡算法

1.3 自定义ribbon负载均衡策略第12张

package com.lxl.www.gateway.myrule;

import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.ribbon.NacosServer;
import com.alibaba.nacos.api.exception.NacosException;
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.BaseLoadBalancer;
import com.netflix.loadbalancer.Server;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.List;

/**
 * 同集群优先带版本的负载均衡策略
 */@Slf4j
public classTheSameClusterPriorityWithVersionRule extends AbstractLoadBalancerRule {

    @Autowired
    privateNacosDiscoveryProperties discoveryProperties;

    @Override
    public voidinitWithNiwsConfig(IClientConfig iClientConfig) {

    }

    @Override
    publicServer choose(Object o) {
        try{
            //第一步: 获取当前服务的集群名称 和 服务的版本号
            String clusterName =discoveryProperties.getClusterName();
            String version = discoveryProperties.getMetadata().get("version");

            //第二步: 获取当前服务的负载均衡器
            BaseLoadBalancer loadBalancer = (BaseLoadBalancer) this.getLoadBalancer();
            //第三步: 获取目标服务的服务名
            String serviceName =loadBalancer.getName();

            //第四步: 获取nacos提供的服务注册api
            NamingService namingService =discoveryProperties.namingServiceInstance();
            //第五步: 获取所有服务名为serviceName的服务实例
            List<Instance> allInstances =namingService.getAllInstances(serviceName);

            // 第六步: 过滤相同版本的服务实例
            List<Instance> sameVersionInstance = new ArrayList<>();
            for(Instance instance : allInstances) {
                if (instance.getMetadata().get("version").equals(version)) {
                    sameVersionInstance.add(instance);
                }
            }

            // 第七步: 过滤有相同集群的服务实例
            List<Instance> sameClusterInstance = new ArrayList<>();
            for(Instance instance: sameVersionInstance) {
                if(instance.getClusterName().equals(clusterName)) {
                    sameClusterInstance.add(instance);
                }
            }
            // 第八步: 选择合适的服务实例
Instance toBeChooseInstanc;
            if (sameClusterInstance == null || sameClusterInstance.size() == 0) {
                toBeChooseInstanc =WeightedBalancer.chooseInstanceByRandomWeight(sameVersionInstance);
                log.info("同版本不同集群的服务实例--{}", toBeChooseInstanc.getPort());
            } else{
                toBeChooseInstanc =WeightedBalancer.chooseInstanceByRandomWeight(sameClusterInstance);
                log.info("同版本同集群服务实例--{}", toBeChooseInstanc.getPort());
            }
            return newNacosServer(toBeChooseInstanc);
        } catch(NacosException e) {
            e.printStackTrace();
        }
        return null;
    }
}

第二步: 启用自定义负载均衡策略

1.3 自定义ribbon负载均衡策略第13张

1.3 自定义ribbon负载均衡策略第14张

@Configuration
/*@RibbonClients(value = {
        @RibbonClient(name="product", configuration = ProductConfiguration.class),
        @RibbonClient(name = "customer", configuration = CustomerConfiguration.class)
})*/
//使用全局的配置
@RibbonClients(defaultConfiguration = GlobalRibbonConfig.class)
public classCustomeRibbonConfig {

}
@Configuration
public classGlobalRibbonConfig {

    @Bean
    publicIRule getRule() {
        //实现带有权重的负载均衡策略
        //return new MyWeightRule();
        //实现同集群优先的负载均衡策略
        //return new TheSameClusterPriorityRule();
        //实现同版本集群优先的服务负载均衡策略
        return newTheSameClusterPriorityWithVersionRule();
    }
}

第三步:启动服务

1.3 自定义ribbon负载均衡策略第15张

如图, 我们启动了两个服务, 一个order, 一个product, 其中order启动了1个实例, product启动了4个实例.

下面来看看order实例的详情

1.3 自定义ribbon负载均衡策略第16张

属于北京集群, 版本号是v1版本

再来看看product集群的详情

1.3 自定义ribbon负载均衡策略第17张

北京集群有两台实例, 一个版本号是v1,另一个是v2

南京集群有两台实例, 一个是v1, 另一个也是v2

第四步: 现在发起请求

http://localhost:8080/get/product

order集群是北京, 版本是version1. 那么服务应该达到哪台服务器呢? 应该打到北京集群的v1版本服务,端口号是8081的服务器.

1.3 自定义ribbon负载均衡策略第18张

果然,请求达到了8081服务上,

加入这时候, 北京集群的8081宕机了, 流量应该达到南京集群的v1版本的集群上, 端口号是8083

1.3 自定义ribbon负载均衡策略第19张

果然是8083.

那么如果8083也宕机了, 流量会打到v2服务器上么?

没错,不会的, 报错了, 没有服务

1.3 自定义ribbon负载均衡策略第20张

免责声明:文章转载自《1.3 自定义ribbon负载均衡策略》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇自定义控件--CircleImageView(类似于QQ、微信圆形头像自定义控件)my2sql 安装使用下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

LVS简介

负载均衡LVS(Linux Virtual Server)... 1 第1章 LVS负载均衡集群简介... 1 1.1 为什么要学LVS. 1 1.2 LVS网站资料:... 1 1.3 LVS内核模块ip_vs介绍... 1 第2章 LVS-DR直接路由模式... 2 2.1 DR直接路由模式说明... 2 2.1.1 DR-原理图片...

HBase海量数据存储

HBaseHBase是一个基于HDFS的非关系型数据库(海量数据存储) HBase的特点 1.海量数据存储,HBase中的表可以容纳上百亿行x上百万列的数据。 2.列式存储,HBase中的数据是基于列进行存储的,能够动态的增加和删除列。 3.准实时查询,HBase在海量的数据量下能够接近准实时的查询(百毫秒以内) 4.多版本,HBase中每一列的数据都有多...

KETTLE集群搭建

KETTLE集群搭建 说明: 本文档基于kettle5.4 一、集群的原理与优缺点 1.1集群的原理          Kettle集群是由一个主carte服务器和多个从carte服务器组成的,类似于master-slave结构,不同的是’master’处理具体任务,只负责任务的分发和收集运行结果。 Master carte结点收到请求后,把任务分成多个部...

大数据(2)---HDFS集群搭建

一、准备工作   1.准备几台机器,我这里使用VMware准备了四台机器,一个name node,三个data node。   VMware安装虚拟机:https://www.cnblogs.com/nijunyang/p/12001312.html   2.Hadoop生态几乎都是用的java开发的,因此四台机器还需要安装JDK。   3.集群内主机域名...

Redis的高可用

1.持久化:主要作用是数据备份,将数据存储在硬盘,保证数据不会因进程退出而丢失 2.复制: 哨兵和集群都是在复制的基础上实现高可用的,复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复 缺陷:故障恢复无法自动化,写操作无法负载均衡,存储能力受到单机的限制 3.哨兵:在复制的基础上,哨兵实现了自动化的故障恢复。缺陷:写操作无法负载均衡;存...

Jexus 负载均衡

利用Jexus的“多目标反向代理”功能,我们很容易实现多服务器的负载均衡,构成一个WEB服务器集群,大大提高网站的负载能力。 Jexus反向代理有一个特点:如果前端服务器本地网站中有内容,它就会直接使用前端服务器的本地内容,而不会将请求发送给后端服务器。 据我们所知,对于网站,一个ASPX网页上常常会含有图片、JS、CSS等大量的静态文件,其比例甚至可以达...