欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SpringCloud-2.0-周阳(负载均衡 - Ribbon)学习笔记

程序员文章站 2022-06-22 10:00:21
上一篇 :7. 服务注册发现 - Consul文章目录1.1....

上一篇 :7. 服务注册发现 - Consul

1. 概述

1.1 Ribbon 是什么

  • SpringCloud Ribbon 是基于 Netflix Ribbon 实现的一套客户端负载均衡的工具
  • 主要功能是提供客户端的软件负载均衡算法,将 Netflix 的中间服务处连接在一起。
  • Ribbon 的客户端组件提供一系列完整的配置项,如:连接超时、重试等。简单的说就是在配置文件中列出 LoadBalance (LB:负载均衡)后面所有的机器,Ribbon 会自动帮你基于某种规则去连接这些机器

SpringCloud-2.0-周阳(负载均衡 - Ribbon)学习笔记

1.2 负载均衡(LB)

  • 核心作用:就是将用户的请求平摊在多个服务器上,从而达到系统的 High Availability(HA :高可用)

  • 常见的负载均衡软件有 Nginx、Lvs 等

  • Bubbo 和 SpringCloud 都提供了负载均衡,SpringCloud 的负载均衡算法可以自定义

  • 负载均衡算法实现的方式:轮询、权重、随机

  • 负载均衡的简单分类:
    1、集中式

    在服务的 消费者 和 提供者之间使用独立的 LB 设施,如Nginx(反向代理服务器) ,由该设施负载把访问请求通过某种策略发送至服务的提供者

    2、进程式

    将LB逻辑集成到 消费者,消费者 从服务注册中心得到哪些地址可用,然后自己再从这些地址中选出一个合适服务器

Ribbon 就属于进程内 LB ,它只是一个类库,集成与消费者进程,消费者通过他来获取到服务提供者的地址

1.3 架构说明

  • Ribbon其实就是一个软负载均衡的客户端组件,他可以和其他所需请求的客户端结合使用,和eureka结合只是其中的一个实例。
  • Ribbon 在工作时分成两步:
  • 第一步 :先选择 Eureka Server ,它优先选择在同一个区域内负载较少的 Server。
  • 第二步 :再根据用户指定的策略,再从 Server 取到的服务注册列表中 选择一个地址

2. 使用

2.1 RestTemplate 的使用

  1. Ribbon 依赖

    新版的 Eureka 会自动把 Ribbon 也一起导入,所以不需要额外引入依赖

    SpringCloud-2.0-周阳(负载均衡 - Ribbon)学习笔记

  2. getForObject / getForEntity 的使用

  • getForObject 之前的 cloud-consumer-order-80 模块中就已经有用过了
    SpringCloud-2.0-周阳(负载均衡 - Ribbon)学习笔记

  • getForEntity ,这个方法返回的是一个对象

    @GetMapping("/getForEntity/{id}")
    public CommonResult<Payment> getPaymentById2(@PathVariable("id") Long id){
        ResponseEntity<CommonResult> entity = restTemplate.getForEntity(PAYMENT_URL + "/provider/getPaymentById/" + id, CommonResult.class);
    
        if (entity.getStatusCode().is2xxSuccessful()){
            //这个 实体对象 中还包含其他很多信息
            log.info("{状态码: " + entity.getStatusCode() +
                    ", 头信息: " + entity.getHeaders() + "}");
            // 如果成功
            return entity.getBody();
        }else {
            return new CommonResult<>(444, "【查询失败】");
        }
    }
    

    SpringCloud-2.0-周阳(负载均衡 - Ribbon)学习笔记
    SpringCloud-2.0-周阳(负载均衡 - Ribbon)学习笔记

  1. postForObject / postForEntity 的使用
  • postForObject ,之前也写过
    SpringCloud-2.0-周阳(负载均衡 - Ribbon)学习笔记

  • postForEntity

    @GetMapping("/postForEntity")
    public CommonResult<Payment> addPayment2(Payment payment){
        log.info("[=插入数据=]{"+ payment +"}");
        ResponseEntity<CommonResult> entity = restTemplate.postForEntity(PAYMENT_URL + "/provider/addPayment", payment, CommonResult.class);
        if (entity.getStatusCode().is2xxSuccessful()){
            //这个 实体对象 中还包含其他很多信息
            log.info("{状态码: " + entity.getStatusCode() +
                    ", 头信息: " + entity.getHeaders() + "}");
            // 如果成功
            return entity.getBody();
        }else {
            return new CommonResult<>(444, "【查询失败】");
        }
    }
    

    SpringCloud-2.0-周阳(负载均衡 - Ribbon)学习笔记
    SpringCloud-2.0-周阳(负载均衡 - Ribbon)学习笔记

2.2 负载均衡组件 - IRule

  • IRule:根据特定算法从服务列表中选取一个要访问的服务
实现类 策略
com.netflix.loadbalancer.RoundRobinRule 轮询(默认)
com.netflix.loadbalancer.RandomRule 随机
com.netflix.loadbalancer.RetryRule 先按照RoundRobinRule的策略获取服务,如果获取服务失败则在指定时间内会进行重试
WeightedResponseTimeRule 对RoundRobinRule的扩展,响应速度越快的实例选择权重越大,越容易被选择
BestAvailableRule 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
AvailabilityFilteringRule 先过滤掉故障实例,再选择并发较小的实例
ZoneAvoidanceRule 复合判断server所在区域的性能和server的可用性选择服务器
  • 修改负载均衡策略
  1. 修改 cloud-consumer-order-80 模块

  2. 注意

    这个配置负载均衡的类 不能在主应用程序的上下文(也就是 主启动类的同级目录中),所以需要单独的创建一个包

  3. 新建一个包 myRule
    SpringCloud-2.0-周阳(负载均衡 - Ribbon)学习笔记

  4. 新建一个规则类 :MyRule

    @Configuration
    public class MySelfRule {
        @Bean
        public IRule myRule(){
            return new RandomRule();//定义为随机
        }
    }
    
  5. 主启动类添加 @RibbonClient

    @EnableEurekaClient
    @SpringBootApplication
    @RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MySelfRule.class)
    public class OrderMain80 {
        public static void main(String[] args) {
            SpringApplication.run(OrderMain80.class, args);
        }
    }
    
  6. 测试

    启动两个 Provider ,一直发出查询请求,会在 8001、8002 随机选择

2.3 轮询原理

  • 原理(轮询)
    SpringCloud-2.0-周阳(负载均衡 - Ribbon)学习笔记
  • RoundRobinRule 源码分析
    SpringCloud-2.0-周阳(负载均衡 - Ribbon)学习笔记
    SpringCloud-2.0-周阳(负载均衡 - Ribbon)学习笔记
    SpringCloud-2.0-周阳(负载均衡 - Ribbon)学习笔记

2.4 自定义一个负载均衡策略

  • 主要改造 cloud-consumer-order-80 模块
  1. ApplicationContextBean去掉@LoadBalanced
    SpringCloud-2.0-周阳(负载均衡 - Ribbon)学习笔记

  2. 在 8001、8002 的 Controller 中添加一个方法

    /** 用于测试自定义负载均衡 */
    @GetMapping(value = "/payment/lb")
    public String getPaymentLB(){
        return serverPort;
    }
    
  3. 新建一个 lb 的包,并在该包下建一个接口:LoadBalancer
    SpringCloud-2.0-周阳(负载均衡 - Ribbon)学习笔记

    public interface LoadBalancer {
        /** 收集服务器总共有多少台能够提供服务的机器,并放到list里面 */
        ServiceInstance instances(List<ServiceInstance> serviceInstances);
    }
    
  4. 为上面的接口写一个实现类

    @Component
    public class MyLB implements LoadBalancer {
    
        // 用于统计当前的访问次数
        private AtomicInteger atomicInteger = new AtomicInteger(0);
    
        /**
         * @return 当前是第几次访问
         */
        public final int getAndIncrement(){
            int current, next;
            // 自旋锁
            do {
                current = this.atomicInteger.get();
                next = current >= 2147483647 ? 0 : current + 1;
            }while (!this.atomicInteger.compareAndSet(current, next));
            System.out.println("【 当前访问次数 】 next = :"+next);
            return next;
        }
    
        @Override
        public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
            // 通过取余,计算出当前应该是哪一个 Provider 提供服务
            int index = getAndIncrement() % serviceInstances.size();
            ServiceInstance instance = serviceInstances.get(index);
            System.out.println("当前是 【" + instance.getUri() + "】 提供服务");
            return instance;
        }
    }
    
  5. 修改 cloud-consumer-order-80 的 Controller

    /** 引入 自定义 的 LB */
    @Autowired
    private LoadBalancer loadBalancer;
    
    @Autowired
    private DiscoveryClient discoveryClient;
    
    /** 用于测试自定义负载均衡 */
    @GetMapping(value = "/payment/lb")
    public String getPaymentLB(){
        // 根据 ServiceId 获取 Server 集合
        List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
        // 如果没有服务
        if (instances == null || instances.size() <= 0){
            return null;
        }
        
        // 获取 Server 实例
        ServiceInstance serviceInstance = loadBalancer.instances(instances);
        // 通过实例获得该实例的 地址
        URI uri = serviceInstance.getUri();
        return restTemplate.getForObject(uri+"/provider/payment/lb",String.class);
    }
    
  6. 启动项目测试自己的轮询

    SpringCloud-2.0-周阳(负载均衡 - Ribbon)学习笔记

SpringCloud-2.0-周阳(负载均衡 - Ribbon)学习笔记

SpringCloud-2.0-周阳(负载均衡 - Ribbon)学习笔记

  • 控制台输出

    SpringCloud-2.0-周阳(负载均衡 - Ribbon)学习笔记

本文地址:https://blog.csdn.net/weixin_44449838/article/details/110496603

相关标签: SpringCloud Ribbon