• SpringCloud微服务(九)——Ribbon负载均衡


    Ribbon负载均衡服务调用

    SpringCloud 已停更

    github官网:https://github.com/netflix/ribbon

    Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。通过Spring Cloud的封装,可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用。Spring Cloud Ribbon虽然只是一个工具类框架,它不像服务注册中心、配置中心、API网关那样需要独立部署,但是它几乎存在于每一个Spring Cloud构建的微服务和基础设施中。因为微服务间的调用,API网关的请求转发等内容,实际上都是通过Ribbon来实现的,包括后续我们将要介绍的Feign,它也是基于Ribbon实现的工具。所以,对Spring Cloud Ribbon的理解和使用,对于我们使用Spring Cloud来构建微服务非常重要。
    Load Balancer(LB)负载均衡,简单轮询、随机连接。

    Load Balancer(LB)负载均衡:服务端,集中式LB(服务消费方和提供方之间使用独立的LB设施),将用户的请求平摊的分配到多个服务,实现高可用(HA)。软件nginx,LVS,硬件F5等。

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

    依赖

    原依赖:

    <dependency>
        <groupId>com.netflix.ribbongroupId>
        <artifactId>ribbonartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4

    eureka client默认有ribbon依赖

    
    <dependency>
        <groupId>org.springframework.cloudgroupId>
        <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    默认使用

    消费者调用服务提供者集群

    消费者注入或者启动类注入

    @Configuration
    public class ApplicationContextConfig {
    
        @Bean
        @LoadBalanced //默认轮询负载均衡
        public RestTemplate restTemplate() {
            return new RestTemplate();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    使用RestTemplate远程RPC调用。服务提供者默认轮询被访问。

    自定义负载均衡算法

    Ribbon核心组件IRule,负载均衡算法

    在这里插入图片描述

    负载规则替换,注意,不能与主启动类在同一个包下!

    作用是替换ribbon负载均衡规则

    另创建包

    package com.wzq.myrule;
    
    import com.netflix.loadbalancer.IRule;
    import com.netflix.loadbalancer.RoundRobinRule;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * 自定义负载均衡路由规则类
     *
     * @author zzyy
     * @date 2020/3/6 15:15
     **/
    @Configuration
    public class MySelfRule {
    
        @Bean
        public IRule myRule() {
            // 定义为随机
            return new RandomRule();
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    主启动类添加注释:

    @RibbonClient(name = "CLOUD-PAYMENT-SERVICE", configuration = MySelfRule.class)
    
    • 1

    7种负载均衡算法,默认轮询。直接return 算法名字。

    在这里插入图片描述

    轮询算法原理

    rest接口第几次请求次数 % 服务器集群总数量 = 实际调用服务器位置下标,每次服务器重启后,rest接口计数从1开始。

    // 服务发现获取服务实例
    List<ServiceInstance> instances = discoveryClient.geInstance("CLOUD-PAYMENT-SERVICE");
    
    int index = rest接口第几次请求次数 % 服务器集群总数量
    // 该请求次数的服务
    List<index>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    源码:

    public RoundRobinRule() {
        this.nextServerCyclicCounter = new AtomicInteger(0);
    }
    
    private int incrementAndGetModulo(int modulo) {
        int current;
        int next;
        do {
            current = this.nextServerCyclicCounter.get();
            next = (current + 1) % modulo;
        } while(!this.nextServerCyclicCounter.compareAndSet(current, next));
        return next;
    }
    
    //compareAndSet比较错误就换值,CAS
    //nextServerCyclicCounter默认0,compareAndSet(期望值,交换值)
    //默认值是期望值则不变true,不然变为交换值false
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    手写一个负载的算法CAS+自旋锁

    首先提供者8001、8002服务controller层加上

    @GetMapping("/payment/lb")
    public String getPaymentLB() {
        return SERVER_PORT;
    }
    
    • 1
    • 2
    • 3
    • 4

    LoadBalancer接口:

    import org.springframework.cloud.client.ServiceInstance;
    import java.util.List;
    
    /**
     * @InterfaceName: LoadBalancer
     * @description:
     * @author: WZQ
     * @create: 2020/3/7 15:55
     **/
    public interface LoadBalancer {
        ServiceInstance instances(List<ServiceInstance> serviceInstances);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    实现类:

    import org.springframework.cloud.client.ServiceInstance;
    import org.springframework.stereotype.Component;
    
    import java.sql.SQLOutput;
    import java.util.List;
    import java.util.concurrent.atomic.AtomicInteger;
    
    /**
     * @ClassName: MyLB
     * @description:
     * @author: XZQ
     * @create: 2020/3/7 15:55
     **/
    @Component
    public class MyLB implements LoadBalancer {
    
    private AtomicInteger atomicInteger = new AtomicInteger(0);
    
        private final int getAndIncrement() {
      
            int current;
            int next;
        
            do {
                current = this.atomicInteger.get();
                next = current >= Integer.MAX_VALUE ? 0 : current + 1;
                //当前服务索引
                //compareAndSet比较,原值是current,则true,否则atomicInteger=next,false
            } while (!atomicInteger.compareAndSet(current, next));
            System.out.println("第几次访问,次数next:" + next);
        
            return next;
    }
    
    
        @Override
        public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
            int index = getAndIncrement() % serviceInstances.size();
            return serviceInstances.get(index);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    controller类中添加:

    @GetMapping("/consumer/payment/lb")
    public String getPaymentLB() {
        //获取服务实例数
        List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
        if (instances == null || instances.size() <= 0) {
            return null;
        }
    
        ServiceInstance serviceInstance = loadBalancer.instances(instances);
        URI uri = serviceInstance.getUri();
    
        return restTemplate.getForObject(uri + "/payment/lb", String.class);
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
  • 相关阅读:
    北理工操作系统实验合集 | API解读与例子(持续更新)
    剪绳子(进阶版)
    【改进灰狼优化算法】贪婪的非分层灰狼优化算法(Matlab代码实现)
    贪心算法—Problem Q
    T-SQL——关于数据合并(Merge)
    Linux:Termius连接本地虚拟机与虚拟机快照
    第五章:双指针与离散化的映射
    CentOS上搭建SVN并自动同步至web目录
    苍穹外卖-day11
    .NET性能优化-使用SourceGenerator-Logger记录日志
  • 原文地址:https://blog.csdn.net/qq_43409401/article/details/127999213