SpringCloud Ribbon负载均衡的实现及自定义负载均衡

之前的文章中我们简单介绍了一下微服务系统架构中引入Ribbon负载均衡的集成
接下来我们会系统的介绍一下Ribbon的实现及自定义策略负载均衡

1)项目的基础结构:
在这里插入图片描述
在一个微服务中我们存在一个共有api
一个统一的客户端(服务消费者)80
服务注册中心的集群 eureka
服务的提供者(多个

Ribbon应用的思维导图:
在这里插入图片描述
Ribbon是一个客户端实现负载均衡的方案,集成在我们的编码阶段,区别于nginx的不同是不需要搭建服务器来实现
其核心主要为:

  • 获取注册中心的服务
  • 通过用户定义的负载均衡的策略选择服务的提供者(默认采用轮询策略

Ribbon的核心策略类为IRule:其中包含的策略有
在这里插入图片描述
后面我们会具体介绍这几种策略

2)实现Ribbon负载均衡
在这里插入图片描述
根据官方描述:
可以使用@RibbonClient实现Ribbon的负载均衡,但是实现类必须是@Configuration且不能与主启动类存在与同一级下,所以我们的客户端项目结构为
在这里插入图片描述
3)修改负载均衡的策略

@Configuration
public class MyRule {

    @Bean
    public IRule myIRule(){
        return new RandomRule(); //随机
    }

}

4)配置主启动类使用我们的负载均衡配置

@SpringBootApplication
@EnableEurekaClient
//在启动时加载我们自定义的负载均衡组件,自定义组件必须是@Configuration,他会替换已有的组件,从而使用我们自定义的负载均衡组件
@RibbonClient(name = "peo_user",configuration = MyRule.class)
public class ConApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConApplication.class,args);
    }

}

至此我们就完成了Ribbon的负载均衡的实现,当然,在实际开发中,IRule提供的负载均衡的策略不一定满足我们服务器的配置需求,这时候就需要我们实现自定义的负载均衡的算法策略,下面我们就介绍一下Ribbon提供的负载均衡的策略及如何实在自定义的负载均衡策略

上面我们介绍到Ribbon的核心组件是IRule,是所有负载均衡算法的父接口,其下有
在这里插入图片描述

  • RoundRobinRule :轮询策略,即依次使用存活的服务
  • RandomRule : 随机策略,每次请求会产生一个随机的服务提供访问
  • AvailabilityFilteringRule :过滤轮询策略,他会先过滤掉跳闸、故障、超过并发阈值的服务,对剩余服务使用轮询策略
  • WeightedResponseTimeRule : 权重策略,根据平均响应时间计算所有服务的权重,响应时间越快服务权重越大被选中的概率越高。刚启动时,如果统计信息不足,则使用轮询策略,等信息足够,切换到 WeightedResponseTimeRule
  • RetryRule : 重试,先按照轮询策略获取服务,如果获取失败则在指定时间内重试,获取可用服务
  • BestAvailableRule :选过滤掉多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
  • ZoneAvoidanceRule : 符合判断server所在区域的性能和server的可用性选择服务

以上的几种策略都继承AbstractLoadBalancerRule

下面简单介绍一下随机策略的实现源码,其余实现大家可自行阅读源码

public class RandomRule extends AbstractLoadBalancerRule {
    public RandomRule() {
    }

    @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) {
                if (Thread.interrupted()) {
                    return null;
                }

                List<Server> upList = lb.getReachableServers();//获取现存的服务
                List<Server> allList = lb.getAllServers();//获取所有的服务,包含已经死掉的服务
                int serverCount = allList.size();
                if (serverCount == 0) {
                    return null;
                }

                int index = this.chooseRandomInt(serverCount);//产生一个范围随机数
                server = (Server)upList.get(index); //获得存活的服务
                if (server == null) {
                    Thread.yield();
                } else {
                    if (server.isAlive()) {
                        return server;
                    }

                    server = null;
                    Thread.yield();
                }
            }

            return server;
        }
    }

    protected int chooseRandomInt(int serverCount) {
        return ThreadLocalRandom.current().nextInt(serverCount);
    }

    public Server choose(Object key) {
        return this.choose(this.getLoadBalancer(), key);
    }

    public void initWithNiwsConfig(IClientConfig clientConfig) {
    }
}

通过注解我们可以看出,其实就是实现了一个简单的算法,通过一个范围随机数来指定此次访问的服务为哪一个。

重点来了-------
重点来了-------
重点来了-------

既然我们已经了解了Ribbon负载均衡的算法实现及原理,那么我们就可以实现我们自己的负载均衡策略

  • 集成AbstractLoadBalancerRule
  • 添加实现方法
  • 编写自己的算法策略
  • 依据上面的配置修改为我们自己的策略

描述:每个服务提供五次访问,满五次以后切换到下一个服务,当所有服务都使用完毕后从第一个服务继续开始,编码如下

public class MyBalancerRule extends AbstractLoadBalancerRule {

    private int total = 0; //服务被调用次数
    private int currentIndex = 0; //当前提供服务的服务下标

    public MyBalancerRule(){

    }

    public void initWithNiwsConfig(IClientConfig iClientConfig) {

    }

    public Server choose(Object key) {
        return this.choose(this.getLoadBalancer(), key);
    }

    /**
     * 自定义策略,访问五次更换服务
     */
    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        } else {
            Server server = null;

            while(server == null) {
                if (Thread.interrupted()) {
                    return null;
                }

                List<Server> upList = lb.getReachableServers(); //获取现存的服务
                List<Server> allList = lb.getAllServers(); //获取所有的服务,包含已经死掉的服务
                int serverCount = allList.size();
                if (serverCount == 0) { //如果不存在服务,返回
                    return null;
                }

                if(total < 5){ //服务未被调用五次,可以继续使用当前服务
                    server = upList.get(currentIndex); //获取当前服务
                    total++; //增加服务调用次数
                }else{ //服务已被调用五次,需要更换服务
                    total = 0; //归零服务被调用次数
                    currentIndex++; //下移当前被调用服务下标
                    if(currentIndex > upList.size())currentIndex = 0; //如果当前下标大于现存的服务个数,则从头开始
                    server = upList.get(currentIndex); //获取当前服务
                }

                if (server == null) {
                    Thread.yield();
                } else {
                    if (server.isAlive()) {
                        return server;
                    }
                    server = null;
                    Thread.yield();
                }
            }

            return server;
        }
    }
}
@Configuration
public class MyRule {

    @Bean
    public IRule myIRule(){
        return new MyBalancerRule(); //自定义负载均衡策略
    }

}

我们也可以使用配置文件来配置:

eureka.client.service-url.defaultZone=http://localhost:7001/eureka/,http://localhost:7002/eureka/
server.port=80
spring.application.name=pro_user
springboot-eureka-clent.ribbon.NFLoadBalancerRuleClassName=com.balance.config.MyBalancerRule

补充知识
在非eureka环境下使用Ribbon

#取消Ribbon使用Eureka
ribbon.eureka.enabled=false

#配置Ribbon能访问 的微服务节点,多个节点用逗号隔开
microservice-provider-user.ribbon.listOfServers=localhost:7001,localhost:7002


源码地址:下载地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序小达人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值