Ribbon基础原理

1、Ribbon的概述

Ribbon是Netflix 发布的开源项目。主要功能是提供 客户端的软件负载均衡算法和服务调用。Ribbon客户端组件提供一系列完善的配置项如连接超时、重试等。

就是 负载均衡 + RestTemplate调用

2、Ribbon的作用

Ribbon在工作时分成两步:

  • 先选择 Eureka Server ,它优先选择在同一个区域内负载较少的server。
  • 再根据用户指定的策略,在从Server取到的服务注册列表中选择一个地址。其中Ribbon提供了多种策略:比如轮询随机根据相应时间加权

2.1、LoadBalancer(负载均衡)

简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的 HA(高可用)。

常见的负载均衡软件有:Nginx、LVS,硬件 F5 等。

2.1.1、集中式LB

即在服务的消费方提供之间使用独立的 LB 设施(可以是硬件 如 F5,也可以是软件,如Nginx),由该设施负责访问请求通过某种策略转发至服务的提供方。

2.1.2、进程内LB

2.2、Ribbon本地负载均衡客户端 VS Nginx 服务端负载均衡区别

Nginx是服务器负载均衡客户端所有请求都会交给 nginx,然后有Nginx实现转发请求。即负载均衡是由服务端实现的

Ribbon本地负载均衡,在调用微服务接口时候,会在注册中心上获取注册信息服务列表之后缓存到JVM本地,从而实现RPC远程服务调用技术。

3、Ribbon的核心思想

4、Ribbon的核心组件IRule

根据特定算法中从服务列表中选取一个要访问的服务:

  • com.netflix.loadbalancer.RoundRobinRule轮询
    C:\Users\20296\AppData\Roaming\Typora\typora-user-images\1594339923233.png
  • com.netflix.loadbalancer.RandomRule随机轮询
    在这里插入图片描述
    在这里插入图片描述
  • com.netflix.loadbalancer.RetryRule (先按照RoundRobinRule(轮询)的策略获取服务,如果获取服务失败则在指定时间内会进行重试,获取可用的服务)
    在这里插入图片描述
  • WeightedResponseTimeRule(对RoundRobinRule的扩展,响应速度越快的实例选择权越大越容易选择
  • BestAvailableRule(会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务)
  • AvailabilityFilteringRule(先过滤故障实例,再选择并发较小的实例)
  • ZoneAvoidanceRule(默认规则,复合判断server所在区域的性能和server的可用性选择服务器)

Ribbon基础原理_第1张图片

修改轮询算法的IRule接口有以上这些实现类

4.1、如何替换轮询

因为Ribbon 是在消费者端的负载负载均衡的,所以就以修改 cloud- consumer-order80这个子项目:

  • 在修改时需要注意的配置细节:
    • 这个自定义配置类不能放在**@ComponentScan所扫描的当前包下以及子包下**,否则我们自定义的这个配置类就会被所有的 Ribbon客户端所共享,达不到特殊化定制的目的。

    • 所以需要新创建一个包,这是当前的包名Ribbon基础原理_第2张图片

    • @ComponentScan这个注解其实就是在@springBootApplication注解的里边。Ribbon基础原理_第3张图片

    • 所以需要将自定义的轮询类放在当前包或者是子包的外面!Ribbon基础原理_第4张图片

/**
 * 自定义的轮询替换默认的轮询
 * @author success
 * @version 1.0
 * @date 2020/7/9 16:16
 */
@Configuration
public class MySelfRule {

    @Bean
    public IRule myRule(){
        //定义为随机的轮询
        return new RandomRule();
    }
}

/**
*以及在主启动类上面添加一个新的注解 @RibbonClient
*其中 name属性 表示当前客户端是去访问支付微服务,
*configuration属性 是将默认出产的Rule替换成自己定义的Rule
*/
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MySelfRule.class)
public class OrderMain80 {
    public static void main(String[] args) {
        SpringApplication.run(OrderMain80.class,args);
    }
}

4.2、Ribbon负载轮询算法

4.2.1、原理

Ribbon 默认使用的轮询算法是 —> RoundRobinRule(循环轮询)

在这里插入图片描述

是继承了 抽象负载均衡器规则(AbstractLoadBalancerRule)

在这个类中有一个 incrementAndGetModulo (增加并获取模数)的方法

Ribbon基础原理_第5张图片

这个方法带一个参数 modulo

其中在方法注释上也写了 是绑定计数器值的模

在这里插入图片描述

大白话原理来了:

看 Eureka 注册中心的注册表上

Ribbon基础原理_第6张图片

总共只有2台 关于支付订单微服务的服务器,然后

List = 2 instance
再看 公式 1 % 2 = 1 --->index = list.get(index) 这是第一次访问
第二次访问 2 % 2 = 0 ---> index = list.get(index)
再进行第三次访问 3 % 2 = 1 ---> .........
接下去循环
知道将全部停止之后,重新启动服务,之前访问的都将归零。

4.3、手写 轮询算法

4.3.1、在支付微服务的controller层中添加一个方法

@Value("${server.port}")
private static final String serverPort ;

@GetMapping(value = "/payment/lb")
public String getPayment(){
	return serverPort;
}

4.3.2、改造消费者客户端微服务

4.3.2.1、在 ApplicationContextConfig 中去掉注解@LoadBalanced

如图:Ribbon基础原理_第7张图片

4.3.2.2、再自己定义一个负载均衡器接口

Ribbon基础原理_第8张图片

Ribbon基础原理_第9张图片

4.3.2.3、实现自定义的负载均衡器
package cn.success.springcloud.lb.impl;

import cn.success.springcloud.lb.LoadBalanced;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 自定义负载均衡器的实现类
 * @author success
 * @version 1.0
 * @date 2020/7/9 19:58
 * 使用 @Component 注解让容器能够扫描到相应的内容
 */
@Component
public class MyLoadBalanced implements LoadBalanced {

    /**
     * 创建一个原子性类,并初始化
     */
    private AtomicInteger atomicInteger = new AtomicInteger(0);

    /**
     * 创建一个 得到并增加的方法来取出到底是哪个服务器在提供服务
     * 使用 CAS和自旋锁,必须创建 AtomicInteger实例
     * @return
     */
    public final int getAndIncrement (){
        int current = 0;
        int next = 0;
        do{
            //得到当前的原子整形
            current = this.atomicInteger.get();
            next = current >= Integer.MAX_VALUE ? 0 : current + 1;

        }
        /**
         * 当更新值和期望值不相等是,进行CAS进行自旋
         */
        while (!this.atomicInteger.compareAndSet(current,next));
            System.out.println("当前访问next的次数:"+next);
            return next;
    }

    /**
     *得到当前请求服务器的次数 % 可以提供服务的实例大小 == 实际调用服务器的位置下标。
     * @param serviceInstances
     * @return
     */
    @Override
    public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
       int index = getAndIncrement() % serviceInstances.size();
        return serviceInstances.get(index);
    }
}

4.3.2.4、在controller层中添加一个getLoadBalanced()方法

Ribbon基础原理_第10张图片

Ribbon基础原理_第11张图片

你可能感兴趣的:(SpringCloud,java,分布式)