企业网站定制开发【Spring Cloud】Ribbon负载均衡策略介绍以及自定义负载均衡实现

企业网站定制开发负载均衡的实现方式

  • 企业网站定制开发客户端的负载均衡
  • 企业网站定制开发服务端的负载均衡(经常使用nginx来实现)

企业网站定制开发服务端负载均衡

  1. 接收请求
  2. 企业网站定制开发企业网站定制开发选择服务器地址
  3. 转发请求

企业网站定制开发客户端负载均衡

  1. 选择服务器地址
  2. 发请求

企业网站定制开发也可以分为企业网站定制开发企业网站定制开发集中式负载均衡企业网站定制开发进程内负载均衡

集中式负载均衡

企业网站定制开发即在服务的消费方和提企业网站定制开发供方之间使用独立的负企业网站定制开发载均衡设施(可以是硬件,如F5,可以是软件,如nginx),由该实施负责把访问请求通过某种策略转发至服务的提供方

进程内负载均衡

将负载均衡逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器。
就属于进程内负载均衡,它只是一个类库,集成于消费方进程,消费方通过它来获取服务提供方的地址

Ribbon的简单介绍

Spring Cloud Ribbon是基于Netfilx Ribbon实现一套客户端负载均衡的工具。简单的说,Ribbon是Netfilx 发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用。Ribbon客户端组件提供一系列完善的配置项,如:连接超时、重试等。
简单的说,就是在配置文件列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如:简单轮询、随机连接等)去连接这些机器。
我们很容易使用Ribbon实现自定义负载均衡算法。

Ribbon 注册到 server之后,Ribbon会从nacos server获取服务列表

Ribbon 负载均衡策略的简单介绍

IRule 接口的实现类定义了一系列负载规则

IRule的类图

负载策略的大致功能实现

策略名策略声明策略描述实现说明
BestAvailableRulepublic class BestAvailableRule extends ClientConfigEnabledRoundRobinRule选择一个最小的并发请求的server逐个考察Server,如果Server被tripped了,则忽略,在选择其中ActiveRequestsCount最小的server
AvailabilityFilteringRulepublic class AvailabilityFilteringRule extends PredicateBasedRule过滤掉那些因为一直连接失败的被标记为circuittripped的后端server,并过滤掉那些高并发的的后端server(active connections 超过配置的阈值) 使用一个AvailabilityPredicate来包含过滤server的逻辑,其实就就是检查status里记录的各个server的运行状态
WeightedResponseTimeRulepublic class WeightedResponseTimeRule extends RoundRobinRule根据响应时间分配一个weight,响应时间越长,weight越小,被选中的可能性越低。一个后台线程定期的从status里面读取评价响应时间,为每个server计算一个weight。Weight的计算也比较简单responsetime 减去每个server自己平均的responsetime是server的权重。当刚开始运行,没有形成status时,使用roubine策略选择server。
RetryRulepublic class RetryRule extends AbstractLoadBalancerRule对选定的负载均衡策略机上重试机制。在一个配置时间段内当选择server不成功,则一直尝试使用subRule的方式选择一个可用的server
RoundRobinRulepublic class RoundRobinRule extends AbstractLoadBalancerRuleroundRobin方式轮询选择server轮询index,选择index对应位置的server
RandomRulepublic class RandomRule extends AbstractLoadBalancerRule随机选择一个server在index上随机,选择index对应位置的server
ZoneAvoidanceRulepublic class ZoneAvoidanceRule extends PredicateBasedRule复合判断server所在区域的性能和server的可用性选择server使用ZoneAvoidancePredicate和AvailabilityPredicate来判断是否选择某个server,前一个判断判定一个zone的运行性能是否可用,剔除不可用的zone(的所有server),AvailabilityPredicate用于过滤掉连接数过多的Server。

ResponseTimeWeightedRule已经被弃用,作用和WeightedResponseTimeRule一样。

还是以这篇博客为基础,我们来探究一下Ribbon负载均衡的基本使用

示例

nacos-provider(提供服务)

基本项目结构如下

还是这篇博客的代码,可以去这篇博客的nacos-provider章节查看,我就不搬运过来了

nacos-consumer(消费服务)

基本结构如下

其中包是使用feign调用远程服务不用管它

pom.xml文件

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">    <parent>        <artifactId>springcloud</artifactId>        <groupId>com.xt</groupId>        <version>1.0-SNAPSHOT</version>    </parent>    <modelVersion>4.0.0</modelVersion>    <artifactId>nacos-consumer</artifactId>    <properties>        <maven.compiler.source>8</maven.compiler.source>        <maven.compiler.target>8</maven.compiler.target>    </properties>    <dependencies>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web</artifactId>        </dependency>        <dependency>            <groupId>com.alibaba.cloud</groupId>            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-actuator</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-openfeign</artifactId>        </dependency>        <dependency>            <groupId>org.projectlombok</groupId>            <artifactId>lombok</artifactId>        </dependency>    </dependencies></project>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

application.yml配置文件

server:  port: 8085spring:  application:    name: nacos-consumer  cloud:    nacos:      discovery:        server-addr: 部署nacos server的服务器IP:8848feign:  hystrix:    enabled: true
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

RibbonConfig

写一个ribbon配置类
IRule 接口的实现类定义了一系列负载规则
如果自己不指定,默认使用的就是轮询算法。
先使用RandomRule的随机来做测试

@Configurationpublic class RibbonConfig {    @Bean    public IRule iRule() {//        权重负载策略 nacos的负载均衡实现//        return new NacosRule(); 是spring cloud alibaba 继承了netflix.loadbalancer包的AbstractLoadBalancerRule抽象类的实现//        会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务//        return new BestAvailableRule();//        复合判断server所在区域的性能和server的可用性选择服务器//        return new ZoneAvoidanceRule();//        先过滤掉故障实例,再选择并发较小的实例//        return new AvailabilityFilteringRule();//      对RoundRobinRule 轮询的扩展,响应速度越快的实例选择权重越多大,越容易被选择//        return new WeightedResponseTimeRule();//        return new ResponseTimeWeightedRule(); 已经被弃用//        随机        return new RandomRule();//        先按照RoundRobinRule 轮询的策略获取服务,如果获取服务失败则在指定时间内进行重试,获取可用的服务//        return new RetryRule();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

controller

@RestControllerpublic class TestController {    private final RestTemplate restTemplate;    @Autowired    public TestController(RestTemplate restTemplate) {this.restTemplate = restTemplate;}    @RequestMapping(value = "/echo-restemplate/{str}", method = RequestMethod.GET)    public String echo(@PathVariable String str) {        return restTemplate.getForObject("http://nacos-provider/echo/" + str, String.class);    }    @Autowired    EchoService echoService;    @RequestMapping(value = "/echo-feign/{str}",method = RequestMethod.GET)    public String feign(@PathVariable String str) {        return echoService.echo(str);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

feign(远程调用服务的东西)

@Component@FeignClient(name = "nacos-provider")public interface EchoService {    @RequestMapping(value = "/echo-error/{str}",method = RequestMethod.GET)    String echo(@PathVariable("str") String str);    //fallback实现类    @Component    class EchoServiceFallback implements EchoService{        @Override        public String echo(@PathVariable("str") String str) {            return "接口请求失败";        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

MyLoadBalancer类(自定义负载均衡的实现,我这里写死了,只访问一个实例)

public class MyLoadBalancer extends AbstractLoadBalancerRule{    public MyLoadBalancer() {    }    @SuppressWarnings({"RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"})    public Server choose(ILoadBalancer lb, Object key) {        if (lb == null) {            return null;        } else {            Server server = null;            while(server == null) {                //测试当前线程是否被中断(检查中断标志),返回一个boolean并清除中断状态,第二次再调用时中断状态已经被清除,将返回一个false。                if (Thread.interrupted()) {                    return null;                }                //获取已启动且可访问的服务器。                List<Server> upList = lb.getReachableServers();                //获取所有已知的服务器(可访问和不可访问)                List<Server> allList = lb.getAllServers();                //全部服务的实例个数                int serverCount = allList.size();                if (serverCount == 0) {                    return null;                }                //RandomRule使用ThreadLocalRandom获取随机数,我这里直接写死,我只要1实例提供服务                int index = 1;                server = (Server)upList.get(index);                if (server == null) {                    //放出CPU资源                    Thread.yield();                } else {                    if (server.isAlive()) {                        return server;                    }                    server = null;                    Thread.yield();                }            }            return server;        }    }    protected int chooseRandomInt(int serverCount) {        //ThreadLocalRandom,在多线程下,它为每个线程维护一个 seed 变量        return ThreadLocalRandom.current().nextInt(serverCount);    }    @Override    public Server choose(Object key) {        return this.choose(this.getLoadBalancer(), key);    }    @Override    public void initWithNiwsConfig(IClientConfig clientConfig) {    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67

NacosConsumerApplication启动类

使用RestTemplate来请求服务,向Spring的IOC注入一个bean: restTemplate;并通过@LoadBalanced注解表明这个restRemplate开启负载均衡的功能。

@SpringBootApplication@EnableDiscoveryClient@EnableFeignClients@RibbonClient(name="nacos-provider",configuration= RibbonConfig.class)public class NacosConsumerApplication {//    @Bean//    @Scope(value = "prototype")//    public IRule loadBalanceRule() {//        return new NacosRule();//    }    @Bean    @LoadBalanced    public RestTemplate restTemplate() {        return new RestTemplate();    }    public static void main(String[] args){        SpringApplication.run(NacosConsumerApplication.class, args);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

像这篇博客一样,先开启三个nacos-provider服务。再开启一个nacos-consumer服务

登录服务器部署的nacos服务的控制台(默认账号和密码都是nacos)

服务器IP:8848/nacos
  • 1

我们可以看到我们注册好的4个服务实例

测试Ribbon自带的随机策略

配置类,设置成 RandomRule

 return new RandomRule();
  • 1

如下所示,将RandomRule注入到Spring 的IOC 容器中进行管理

@Configurationpublic class RibbonConfig {    @Bean    public IRule iRule() {//        权重负载策略 nacos的负载均衡实现//        return new NacosRule(); 是spring cloud alibaba 继承了netflix.loadbalancer包的AbstractLoadBalancerRule抽象类的实现//        会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务//        return new BestAvailableRule();//        复合判断server所在区域的性能和server的可用性选择服务器//        return new ZoneAvoidanceRule();//        先过滤掉故障实例,再选择并发较小的实例//        return new AvailabilityFilteringRule();//      对RoundRobinRule 轮询的扩展,响应速度越快的实例选择权重越多大,越容易被选择//        return new WeightedResponseTimeRule();//        return new ResponseTimeWeightedRule(); 已经被弃用//        随机        return new RandomRule();//        先按照RoundRobinRule 轮询的策略获取服务,如果获取服务失败则在指定时间内进行重试,获取可用的服务//        return new RetryRule();    }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

访问nacos-consumer服务,然后nacos-consumer服务访问请求nacos-provider服务,点击刷新多次

1号provider服务实例

2号provider服务实例

3号provider服务实例

可以看出,确实是随机策略

测试自定义的负载均衡策略

修改RibbonConfig,向Spring IOC容器中注入MyLoadBalancer

return new MyLoadBalancer();
  • 1
@Configurationpublic class RibbonConfig {    @Bean    public IRule iRule() {//        权重负载策略 nacos的负载均衡实现//        return new NacosRule(); 是spring cloud alibaba 继承了netflix.loadbalancer包的AbstractLoadBalancerRule抽象类的实现//        会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务//        return new BestAvailableRule();//        复合判断server所在区域的性能和server的可用性选择服务器//        return new ZoneAvoidanceRule();//        先过滤掉故障实例,再选择并发较小的实例//        return new AvailabilityFilteringRule();//      对RoundRobinRule 轮询的扩展,响应速度越快的实例选择权重越多大,越容易被选择//        return new WeightedResponseTimeRule();//        return new ResponseTimeWeightedRule(); 已经被弃用//        随机//        return new RandomRule();//        先按照RoundRobinRule 轮询的策略获取服务,如果获取服务失败则在指定时间内进行重试,获取可用的服务//        return new RetryRule();                //自己的负载均衡策略,只访问可访问服务列表的下标为1的服务实例        return new MyLoadBalancer();            }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

重新运行nacos-consumer服务实例
然后再次使用浏览器访问nacos-consumer服务,让他去消费nacos-provider服务。

我多次点击刷新浏览器,只有3号provider服务实例的被调用次数在增加,说明我们的修改生效了。

注意:虽然我的负载均衡策略是设置的活动服务实例列表中的下标为1的服务实例接收消费。这里虽然是3号provider实例,但是下标为1是指列表里面的下标为1

//获取已启动且可访问的服务器。List<Server> upList = lb.getReachableServers();
  • 1
  • 2

References:

  • https://www.cnblogs.com/roytian/p/12176321.html
  • https://zhuanlan.zhihu.com/p/180300022
  • https://www.jianshu.com/p/861ed1960014

(写博客主要是对自己学习的归纳整理,资料大部分来源于书籍、网络资料和自己的实践,整理不易,但是难免有不足之处,如有错误,请大家评论区批评指正。同时感谢广大博主和广大作者辛苦整理出来的资源和分享的知识。)

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发