Ribbon源码追踪

1.Ribbon是什么?

Ribbon是Netflix发布的负载均衡器,它有助于控制HTTP和TCP的客户端的行为。为Ribbon配置服务提供者地址后,Ribbon就可基于某种负载均衡算法,自动地帮助服务消费者去请求。Ribbon默认为我们提供了很多负载均衡算法,例如轮询、随机等。当然,我们也可为Ribbon实现自定义的负载均衡算法。

在Spring Cloud中,当Ribbon与Nacos配合使用时,Ribbon可自动从Nacos Server获取服务提供者地址列表,并基于负载均衡算法,请求其中一个服务提供者实例。展示了Ribbon与Nacos配合使用时的架构。
在这里插入图片描述

2.源码跟踪

为什么我们只输入了service名称就可以访问了呢?之前还要获取ip和端口。显然有人帮我们根据service名称,获取到了服务实例的ip和端口。它就是LoadBalancerInterceptor
我们进行源码跟踪:
在这里插入图片描述
继续跟入execute方法:发现获取了8001端口的服务

org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient

在这里插入图片描述
如果再跟下一次,发现获取的是8002

2.负载均衡策略

Ribbon默认的负载均衡策略是简单的轮询,我们可以测试一下:

编写测试类,在刚才的源码中我们看到拦截中是使用RibbonLoadBalanceClient来进行负载均衡的,其中有一个choose方法,是这样介绍的:
在这里插入图片描述
现在这个就是负载均衡获取实例的方法。我们对注入这个类的对象,然后对其测试:

package com.bruceliu.test;

import com.bruceliu.SpringcloudDemoConsumerApplication;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * @author bruceliu
 * @create 2019-05-04 11:33
 * @description 负载均衡算法测试
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringcloudDemoConsumerApplication.class)
public class LoadBalanceTest {
    
    

    @Autowired
    RibbonLoadBalancerClient client;

    @Test
    public void test1(){
    
    
        for (int i = 0; i <10 ; i++) {
    
    
            ServiceInstance instance = this.client.choose("SPRINGCLOUD-DEMO-SERVICE");
            System.out.println(instance.getHost() + ":" + instance.getPort());
        }
    }
}

运行结果:
在这里插入图片描述
符合了我们的预期推测,确实是轮询方式

我们是否可以修改负载均衡的策略呢?继续跟踪源码,发现这么一段代码:
在这里插入图片描述
我们看看这个rule是谁:
在这里插入图片描述
这里的rule默认值是一个RoundRobinRule,看类的介绍:
在这里插入图片描述
这不就是轮询的意思嘛。

我们注意到,这个类其实是实现了接口IRule的,查看一下:
在这里插入图片描述
定义负载均衡的规则接口。
它有以下实现:
在这里插入图片描述
SpringBoot也帮我们提供了修改负载均衡规则的配置入口:

SPRINGCLOUD-DEMO-SERVICE:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

格式是:{服务名称}.ribbon.NFLoadBalancerRuleClassName,值就是IRule的实现类。
再次测试,发现结果变成了随机:
在这里插入图片描述

2.1 Ribbon核心组件IRule(面试题)

在这里插入图片描述

策略名称 策略对应的类名 实现原理
轮询策略(默认) RoundRobinRule 轮询策略表示每次都顺序取下一个 provider,比如一共有 5 个provider,第 1 次取第 1 个,第 2次取第 2 个,第 3 次取第 3 个,以此类推
权重轮询策略 WeightedResponseTimeRule 1.根据每个 provider 的响应时间分配一个权重,响应时间越长,权重越小,被选中的可能性越低。2.原理:一开始为轮询策略,并开启一个计时器,每 30 秒收集一次每个 provider 的平均响应时间,当信息足够时,每个 provider附上一个权重,并按权重随机选择provider,高权越重的 provider会被高概率选中。
随机策略 RandomRule 从 provider 列表中随机选择一个provider
最少并发数策略 BestAvailableRule 选择正在请求中的并发数最小的 provider,除非这个provider 在熔断中。
在“选定的负载均衡策略”基础上进行重试机制 RetryRule 1.“选定的负载均衡策略”这个策略是轮询策略RoundRobinRule 2.该重试策略先设定一个阈值时间段,如果在这个阈值时间段内当选择 provider 不成功,则一直尝试采用“选定的负载均衡策略:轮询策略”最后选择一个可用的provider
可用性敏感策略 AvailabilityFilteringRule 过滤性能差的 provider,有 2种:第一种:过滤掉在 eureka 中处于一直连接失败 provider 第二种:过滤掉高并发的 provider
区域敏感性策略 ZoneAvoidanceRule 1.以一个区域为单位考察可用性,对于不可用的区域整个丢弃,从剩下区域中选可用的provider2.如果这个 ip 区域内有一个或多个实例不可达或响应变慢,都会降低该 ip 区域内其他 ip 被选中的权重。

2.2.修改访问服务的算法方式

方式一:修改代码更换负载均衡策略

第一步:新建一个不会被@ComponentScan组件扫描到的包,如:com.rules

第二步:在该包下新建自己的负载均衡算法的规则类

第三步:主启动类上添加注解:@RibbonClient

package com.rules;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import com.netflix.loadbalancer.RoundRobinRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @BelongsProject: MicroService
 * @BelongsPackage: com.rules
 * @CreateTime: 2020-11-18 16:50
 * @Description: TODO
 */
@Configuration
public class MyLoadBalanceRule {
    
    


    /**
     * @desc 自定义负载均衡规则,默认是轮询规则
     * @return
     */
    @Bean
    public IRule myRule(){
    
    
        //return new RandomRule(); // 改为随机算法规则
        return new RoundRobinRule(); // 轮询
    }

}




@EnableEurekaClient //开启客户端
@SpringBootApplication
@RibbonClient(name = "PRODUCT-SERVICE",configuration = MyLoadBalanceRule.class)
public class ProtalApp80 {
    
    

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

注意: 这里这个类不能配置到SpringBoot启动类的同级别目录下以及子目录下,为什么呢?因为Ribbon的配置必须用@Configuration注解标识,并且不能被@Component注解或者@SpringBootApplication(因为里面包含了@Component)扫描到。因为如果被@ComponetScan扫描到会导致所有的RibbonClient都去共享这个配置。

方式二:修改配置文件更换负载均衡策略
第二种方式在application.properties中设置分配的策略

springcloud-alibaba-provider:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

'springcloud-alibaba-provider’是调用的服务的名称,后面的组成部分是固定的。
同时注释掉方式一中的内容

猜你喜欢

转载自blog.csdn.net/BruceLiu_code/article/details/114579991