SpringCloud之Ribbon与Loadbalance的使用以及原理

目录

1、Ribbon

1-1、负载均衡的两种方式

1-2、手写一个客户端侧负载均衡器

1-3、使用Ribbon实现负载均衡

1-4、Ribbon的重要接口 以及内置负载均衡规则

1-4-1、Ribbon重要接口

1-4-2、Ribbon负载均衡规则

1-5、Ribbon的配置

1-5-1、类配置方式

1-5-2、属性配置

1-5-3、优先级高低

1-5-4、全局配置

1-6、饥饿加载

2、Loadbalance

2-1、Ribbon和Loadbalance 对比

2-2、整合LoadBlance

2-2-1、升级版本

2-2-2、移除ribbon依赖,增加loadBalance依赖

2-3、自定定义负载均衡器

2-4、重试机制

2-5、源码分析

2-5-1、源码的实现

2-5-2、初始化过程

2-5-3、获取负载均衡器

2-5-4、获取实例

2-5-5、获取服务实例列表


1、Ribbon

1-1、负载均衡的两种方式

1、服务器端负载均衡:

传统的方式前端发送请求会到我们的的nginx上去,nginx作为反向代理,然后路由给后端的服务器,由于负载均衡算法是nginx提供的,而nginx是部署到服务器端的,所以这种方式又被称为服务器端负载均衡。

SpringCloud之Ribbon与Loadbalance的使用以及原理_第1张图片

2、客户端侧负载均衡:

现在有三个实例,内容中心可以通过discoveryClient 获取到用户中心的实例信息,如果我们再订单中心写一个负载均衡 的规则计算请求那个实例,交给restTemplate进行请求,这样也可以实现负载均衡,这个算法里面,负载均衡是有订单中心提供的,而订单中心相对于用户中心是一个客户端,所以这种方式又称为客户端负负载均衡。

SpringCloud之Ribbon与Loadbalance的使用以及原理_第2张图片

1-2、手写一个客户端侧负载均衡器

@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/order/create")
public String createOrder(Integer productId,Integer userId){
    List instances = discoveryClient.getInstances("aiqingyu-stock");
    List targetUrls = instances.stream()
        // 数据变换
        .map(instance -> instance.getUri().toString() + "/stock/reduce")
        .collect(Collectors.toList());
    int i = ThreadLocalRandom.current().nextInt(targetUrls.size());
    String targetUrl = targetUrls.get(i);
    log.info("请求求目标地址:{}",targetUrl);
    String result = restTemplate.getForObject(targetUrl +"/"+ productId, String.class);
    log.info("进行减库存:{}",result);
    return "下单成功";
}

1-3、使用Ribbon实现负载均衡

Ribbon是什么,Netflix开源的客户端侧负载均衡器。更加直观说就是ribbon就是简化我们这段代码的小组件,不过它比我们的代码要强大一些,它给我们提供了丰富的负载均衡算法。

SpringCloud之Ribbon与Loadbalance的使用以及原理_第3张图片

引入ribbon,三步骤:加依赖,启动注解,写配置

不需要加,nacosdiscovery,已经给添加了依赖

SpringCloud之Ribbon与Loadbalance的使用以及原理_第4张图片

写注解,需要写到RestTemplate上面。

SpringCloud之Ribbon与Loadbalance的使用以及原理_第5张图片

第三步:没有配置。

改造请求:

url:改为下面当请求发送的发送的时候ribbon会将aiqingyu-stock进行转化为我们nacos里面中的地址。并且进行负载均衡算法,进行请求

1-4、Ribbon的重要接口 以及内置负载均衡规则

1-4-1、Ribbon重要接口

接口 作用 默认值
IClientConfig 读取配置 DefaultclientConfigImpl
IRule 负载均衡规则,选择实例 ZoneAvoidanceRule
IPing 筛选掉ping不通的实例 默认采用DummyPing实现,该检查策略是一个特殊的实现,
实际上它并不会检查实例是否可用,而是始终返回true,默认认为所
有服务实例都是可用的.
ServerList 交给Ribbon的实例列表 Ribbon: ConfigurationBasedServerList
Spring Cloud Alibaba: NacosServerList
ServerListFilter 过滤掉不符合条件的实例 ZonePreferenceServerListFilter
ILoadBalancer Ribbon的入口 ZoneAwareLoadBalancer
ServerListUpdater 更新交给Ribbon的List的策略 PollingServerListUpdater

1-4-2、Ribbon负载均衡规则

规则名称 特点
RandomRule 随机选择一个Server
RetryRule 对选定的负责均衡策略机上充值机制,在一个配置时间段内当选择Server不成功,则一直尝试使用subRule的方式选择一个可用的Server
RoundRobinRule 轮询选择,轮询index,选择index对应位置Server
WeightedResponseTimeRule 根据相应时间加权,相应时间越长,权重越小,被选中的可能性越低
ZoneAvoidanceRule (默认是这个)该策略能够在多区域环境下选出最佳区域的实例进行访问。在没有Zone的环境下,类似于轮询(RoundRobinRule)

1-5、Ribbon的配置

1-5-1、类配置方式

public class RibbonConfiguration {
    @Bean
    public IRule ribbonRule(){
        //随机选择
        return new RandomRule();
    }
}
/**
* 指定配置
**/
@Configuration
@RibbonClient(name = "msb-stock",configuration = RibbonConfiguration.class)
public class UserRibbonConfiguration {
}

1-5-2、属性配置

将前面的配置注释掉,在yml配置文件中,如下进行配置:

aiqingyu-stock:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

1-5-3、优先级高低

java配置的要高, 我们可以类配置的路由规则为随机(RandomRule),然后属性配置为轮训(RoundRobinRule),测试是随机则java配置高于属性配置

1-5-4、全局配置

@RibbonClients(defaultConfiguration=xxx.class)

就是将 RibbonClient 改为 RibbonClients,将 configuration 改为 defaultConfiguration

SpringCloud之Ribbon与Loadbalance的使用以及原理_第6张图片

1-6、饥饿加载

ribbon默认是懒加载的,只有第一层调用的时候才会生成userCenter 的 ribbonClient,这就会导致首次调用的会很慢的问题。

ribbon:
  eager-load:
    enabled: true
      clients: aiqingyu-stock

2、Loadbalance

Spring Cloud LoadBalancer是Spring Cloud官方自己提供的客户端负载均衡器,抽象和实现,用来替代 Ribbon(已经停更)

2-1、Ribbon和Loadbalance 对比

组件 组件提供的负载策略 支持负载的客户端
Ribbon 随机 RandomRule 轮询 RoundRobinRule 重试 RetryRule 最低并发 BestAvailableRule 可用过滤 AvailabilityFilteringRule 响应时间加权重 ResponseTimeWeightedRule 区域权重 ZoneAvoidanceRule Feign或openfeign、RestTemplate
Spring Cloud Loadbalancer RandomLoadBalancer 随机(高版本有,此版本没有RoundRobinLoadBalancer 轮询(默认) Ribbon 所支持的、WebClient

LoadBalancer 的优势主要是,支持响应式编程的方式异步访问客户端,依赖 Spring Web Flux 实现客户端负载均衡调用。

2-2、整合LoadBlance

注意如果是Hoxton之前的版本,默认负载均衡器为Ribbon,需要移除Ribbon引用和增加配置spring.cloud.loadbalancer.ribbon.enabled: false。

2-2-1、升级版本

Spring Cloud Alibaba Spring cloud Spring Boot
2.2.6.RELEASE Spring Cloud Hoxton.SR9 2.3.2.RELEASE

2-2-2、移除ribbon依赖,增加loadBalance依赖



	com.alibaba.cloud
	spring-cloud-starter-alibaba-nacos-discovery
	
		
		
			org.springframework.cloud
			spring-cloud-starter-netflix-ribbon
		
	




	org.springframework.cloud
	spring-cloud-starter-loadbalancer


    org.projectlombok
    lombok

2-3、自定定义负载均衡器

package com.msb.order.loadbalance;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.reactive.DefaultResponse;
import org.springframework.cloud.client.loadbalancer.reactive.EmptyResponse;
import org.springframework.cloud.client.loadbalancer.reactive.Request;
import org.springframework.cloud.client.loadbalancer.reactive.Response;
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import reactor.core.publisher.Mono;
import java.util.List;
import java.util.Random;

public class CustomRandomLoadBalancerClient implements ReactorServiceInstanceLoadBalancer {
 
    // 服务列表
    private ObjectProvider serviceInstanceListSupplierProvider;
 
    public CustomRandomLoadBalancerClient(ObjectProvider serviceInstanceListSupplierProvider) {
        this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
    }
 
    @Override
    public Mono> choose(Request request) {
        ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider.getIfAvailable();
        return supplier.get().next().map(this::getInstanceResponse);
    }
 
    /**
     * 使用随机数获取服务
     * @param instances
     * @return
     */
    private Response getInstanceResponse(
            List instances) {
        System.out.println("进来了");
        if (instances.isEmpty()) {
            return new EmptyResponse();
        }
 
        System.out.println("进行随机选取服务");
        // 随机算法
        int size = instances.size();
        Random random = new Random();
        ServiceInstance instance = instances.get(random.nextInt(size));
 
        return new DefaultResponse(instance);
    }
}
@EnableDiscoveryClient
@SpringBootApplication
// 设置全局负载均衡器
@LoadBalancerClients(defaultConfiguration = {CustomRandomLoadBalancerClient.class})
// 指定具体服务用某个负载均衡
//@LoadBalancerClient(name = "aiqingyu-stock",configuration = CustomRandomLoadBalancerClient.class)
//@LoadBalancerClients(
//        value = {
//                @LoadBalancerClient(value = "aiqingyu-stock",configuration = CustomRandomLoadBalancerClient.class)
//        },defaultConfiguration = LoadBalancerClientConfiguration.class
//)
public class OrderApplication {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

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

2-4、重试机制

spring:
  cloud:
    loadbalancer:
      #以下配置为LoadBalancerProperties 配置类
      clients:
        #default 表示去全局配置,如要针对某个服务,则填写毒地应的服务名称即可
        default:
          retry:
            enbled: true
            #是否有的的请求都重试,false表示只有GET请求才重试
            retryOnAllOperation: true
            #同一个实例的重试次数,不包括第一次调用:比如第填写3 ,实际会调用4次
            maxRetriesOnSameServiceInstance: 3
            #其他实例的重试次数,多节点情况下使用
            maxRetriesOnNextServiceInstance: 0

2-5、源码分析

2-5-1、源码的实现

我们这里是给RestTemplate增加了@LoadBalanced就实现了负载均衡,我们学习Ribbon的时候是也是在RestTemplate上加了@LoadBalanced也实现了负载均衡,当时我们说RestTemplate上面有个扩展点ClientHttpRequestInterceptor, 我们Ribbon通过LoadBalancerInterceptor实现了这个扩展点,将msb-stock替换为 192.168.0.3:8003,如果所示:通过LoadBalancerClient 的实现类 RibbbonLoadBalancerClient 实现负载

SpringCloud之Ribbon与Loadbalance的使用以及原理_第7张图片

那LoadBalancer是不是也是同样的功能呢? LoadBalancerClient 只有一个实现类是BlockingLoadBalancerClient

SpringCloud之Ribbon与Loadbalance的使用以及原理_第8张图片

2-5-2、初始化过程

依旧是以前的逻辑找自动装配类,进入spring-cloud-starer-loadbalnecer:2.2.6.REALEAS,查找spring.factories,发现里面并没有对应spring.factories,这说明的这个starter只是起到jar管理的作用(查看的mybatis和SpringBoot整合的源码的话,会发现也是这样),所以进入pom中会发现应该是在spring-cloud-loadbalancer里面。

SpringCloud之Ribbon与Loadbalance的使用以及原理_第9张图片

分析这里自动配置类BlockingLoadBalancerClientAutoConfiguration和刚才分析的BlockingLoadBalancerClient前边名称一样,那这个应该是重点分析的自动配置类

进入BlockingLoadBalancerClientAutoConfiguration,会发现这里和Ribbon中的配置相似,都是在LoadBalancerAutoConfiguration之前。

SpringCloud之Ribbon与Loadbalance的使用以及原理_第10张图片

而LoadBalancerAutoConfiguration和Ribbon中的配置是一样的,如下:

SpringCloud之Ribbon与Loadbalance的使用以及原理_第11张图片

在BlockingLoadBalancerClientAutoConfiguration中看到一个重要的类BlockingLoadBalancerClient,这个类在前面分析过,通过它,我们进行的负载均衡,里面有个参数是LoadBalancerClientFactory,这个参数在Ribbon中的SpringClientFactory,那哪里创建的它呢

SpringCloud之Ribbon与Loadbalance的使用以及原理_第12张图片

全文搜索会发先:在 LoadBalancerAutoConfiguration里面,这个类注意是在loadbalance包下和上面加载的LoadBalancerAutoConfiguration不是一个

SpringCloud之Ribbon与Loadbalance的使用以及原理_第13张图片

对应加载配置和顺序如下:

SpringCloud之Ribbon与Loadbalance的使用以及原理_第14张图片

2-5-3、获取负载均衡器

RestTemplate发送请求一定经过LoadBalancerInterceptor,中的intercept方法,这里loadBalancer是BlockingLoadBalancerClient

SpringCloud之Ribbon与Loadbalance的使用以及原理_第15张图片

这里获取负载均衡器

SpringCloud之Ribbon与Loadbalance的使用以及原理_第16张图片

SpringCloud之Ribbon与Loadbalance的使用以及原理_第17张图片

SpringCloud之Ribbon与Loadbalance的使用以及原理_第18张图片

这里就是从上面文中获取负载均衡器:RoundRobinLoadBalancer

2-5-4、获取实例

SpringCloud之Ribbon与Loadbalance的使用以及原理_第19张图片

掉用RoundRobinLoadBalancer.choose方法

SpringCloud之Ribbon与Loadbalance的使用以及原理_第20张图片

SpringCloud之Ribbon与Loadbalance的使用以及原理_第21张图片

利用求余的方式选择一个实例,看到这发现实例列表已经获取到了,那什么时候获取到的呢?

2-5-5、获取服务实例列表

我们的服务列表是作为ServiceInstanceListSupplier的一个属性,那我们需要看在哪里创建的这个类:

SpringCloud之Ribbon与Loadbalance的使用以及原理_第22张图片

在LoadBalancerClientConfiguration创建对应的类ServiceInstanceListSupplier

你可能感兴趣的:(spring,cloud,ribbon,java)