• SpringCloud 07 Ribbon实现负载均衡


    7.1 Ribbon实现负载均衡


    我们想要体验负载均衡,其实 更加显著的是,服务提供者和数据库做集群。而不是单纯的注册中心做集群。这样我们 能够 很明确知道它来自于哪个服务。(只要保证 它们的 服务名 一样就行了。

    1. 我们 先要 弄三个 一毛一样的数据库,然后 弄三个 提供者。分别操作这三个数据库。
    create database `db03`;
    
    use `db03`;
    
    drop table if exists `dept`;
    
    create table `dept`(
    	`deptno` bigint(20) not null AUTO_INCREMENT,
    	`dname` varchar(60) default null,
    	`db_source` varchar(60) default null,
    	primary key (`deptno`)
    ) engine=innodb auto_increment=7 DEFAULT CHARSET = utf8 comment='部门表';
    
    insert into dept(dname, db_source) values ('开发部',DATABASE()),
                                              ('人事部',DATABASE()),
                                              ('财务部',DATABASE()),
                                              ('市场部',DATABASE()),
                                              ('运维部',DATABASE());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    三个提供者的代码 都是一样的,只不过 改变了 它们的 启动端口而已。

    在这里插入图片描述

    我们 会发现 这里 就出现了 三个 提供者,但是它们的 服务名 都是一样的。

    先来 设置一下 能够 最大 运行的 项目 数量

    在这里插入图片描述

    好,现在就来观察一下 负载均衡 的效果,我们看下 到底 是不是 会 简单轮询或随机决策呢?

    在这里插入图片描述
    好了,我们 现在 发现 它查询的 是 db2 的。再次查询,看一下。

    在这里插入图片描述
    诶,又变成了 db1 的了。这样 我们 就利用 Ribbon 简单的实现了 负载均衡!


    7.2 自定义负载均衡

    默认的 负载均衡算法是:轮询算法

    根据 最新的动向可知,现在 好像是 不支持 IRule 了。用的全是 LoadBalancer 实现的负载均衡!

    比如我们现在 去查看 一个 随机轮询算法 RandomLoadBalancer

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by FernFlower decompiler)
    //
    
    package org.springframework.cloud.loadbalancer.core;
    
    import java.util.List;
    import java.util.concurrent.ThreadLocalRandom;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.springframework.beans.factory.ObjectProvider;
    import org.springframework.cloud.client.ServiceInstance;
    import org.springframework.cloud.client.loadbalancer.DefaultResponse;
    import org.springframework.cloud.client.loadbalancer.EmptyResponse;
    import org.springframework.cloud.client.loadbalancer.Request;
    import org.springframework.cloud.client.loadbalancer.Response;
    import reactor.core.publisher.Mono;
    
    public class RandomLoadBalancer implements ReactorServiceInstanceLoadBalancer {
        private static final Log log = LogFactory.getLog(RandomLoadBalancer.class);
        private final String serviceId;
        private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;
    
        public RandomLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId) {
            this.serviceId = serviceId;
            this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
        }
    
        public Mono<Response<ServiceInstance>> choose(Request request) {
            ServiceInstanceListSupplier supplier = (ServiceInstanceListSupplier)this.serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
            return supplier.get(request).next().map((serviceInstances) -> {
                return this.processInstanceResponse(supplier, serviceInstances);
            });
        }
    
        private Response<ServiceInstance> processInstanceResponse(ServiceInstanceListSupplier supplier, List<ServiceInstance> serviceInstances) {
            Response<ServiceInstance> serviceInstanceResponse = this.getInstanceResponse(serviceInstances);
            if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) {
                ((SelectedInstanceCallback)supplier).selectedServiceInstance((ServiceInstance)serviceInstanceResponse.getServer());
            }
    
            return serviceInstanceResponse;
        }
    
        private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {
            if (instances.isEmpty()) {
                if (log.isWarnEnabled()) {
                    log.warn("No servers available for service: " + this.serviceId);
                }
    
                return new EmptyResponse();
            } else {
                int index = ThreadLocalRandom.current().nextInt(instances.size());
                ServiceInstance instance = (ServiceInstance)instances.get(index);
                return new DefaultResponse(instance);
            }
        }
    }
    
    • 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
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    首先我们知道肯定要实现这个ReactorServiceInstanceLoadBalancer,并且如果是一个 负载均衡算法类的话,必须要 能够拿到 服务列表,然后 主要的 选择决策 是 choose() 函数

    choose 函数:必须返回 supplier.get().netx().map() 的返回值。

    而这个 map() 接收 的是 函数接口 类型的 的参数,说白了就是要 接收 一个 方法,这个方法 应该就是 我们 实现 负载均衡算法的地方!

    所以 我们只要 弄一个 和 processInstanceResponse() 类似的方法 就行了。

    然后 我们可以 很简单的分析出 DefaultResponse() 是 接收 被选择出来的 服务实例的! 那么 就简单太多了。。我们 只要 根据 自己的 意思来 获取 服务实例,就可以实现 各种各样的 负载均衡算法了!

    1. 根据 Random() 随机数 来实现一个 负载均衡算法
    package top.muquanyu.springcloud.config;
    
    import org.springframework.beans.factory.ObjectProvider;
    import org.springframework.cloud.client.ServiceInstance;
    import org.springframework.cloud.client.loadbalancer.DefaultResponse;
    import org.springframework.cloud.client.loadbalancer.EmptyResponse;
    import org.springframework.cloud.client.loadbalancer.Request;
    import org.springframework.cloud.client.loadbalancer.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<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;
    
        public CustomRandomLoadBalancerClient(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider){
            this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
        }
    
    
        @Override
        public Mono<Response<ServiceInstance>> choose(Request request) {
            ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider.getIfAvailable();
            return supplier.get().next().map(this::getInstanceResponse);
        }
    
        // 负载均衡算法
        // 我们尝试 使用 随机数来 获取服务
    
        private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {
    
            System.out.println("进入到 负载均衡算法里面了!");
    
            // 这个 instances 肯定是 其他东西 提供给我们的
            if(instances.isEmpty()){
                return new EmptyResponse();// 如果 服务实例的列表是空的,则我们也返回一个空的响应!
            }
    
            System.out.println("进行 随机数");
    
            int size = instances.size(); // 服务实例的个数,我们是三个
            System.out.println("服务实例的个数:" + size);
    
            Random random = new Random();
            int randomNum = random.nextInt(size);
    
            System.out.println("当前随机数是:" + randomNum);
            ServiceInstance instance = instances.get(randomNum);
    
            return new DefaultResponse(instance);
        }
    }
    
    • 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
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    1. 自定义 配置类
    package top.muquanyu.springcloud.config;
    
    import org.springframework.cloud.client.loadbalancer.LoadBalanced;
    import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer;
    import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
    import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
    import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.env.Environment;
    import org.springframework.web.client.RestTemplate;
    
    @Configuration
    public class ConfigBean {
    
        // 因为 RestTemplate 没有注册到 IOC 容器中,所以我们 手动 给它装进去
        @Bean
        @LoadBalanced
        public RestTemplate getRestTemplate(){
            return new RestTemplate();
        }
    
        @Bean
        public ReactorServiceInstanceLoadBalancer reactorServiceInstanceLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {
            String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
            //返回随机轮询负载均衡方式
            //return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
                    return new CustomRandomLoadBalancerClient(loadBalancerClientFactory.getLazyProvider(name,ServiceInstanceListSupplier.class));
        }
    }
    
    • 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
    1. 开启 对 某个或多个 服务的 负载均衡 @LoadBalancerClient 和 @LoadBalancerClients
    package top.muquanyu.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
    import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    import top.muquanyu.springcloud.config.ConfigBean;
    
    @SpringBootApplication
    @EnableEurekaClient
    @LoadBalancerClients({@LoadBalancerClient(name = "SPRINGCLOUD-PROVIDER-DEPT", configuration = ConfigBean.class)})
    public class DeptConsumer_80 {
        public static void main(String[] args) {
            SpringApplication.run(DeptConsumer_80.class,args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    Redis中间件(从搭建到弃坑)
    Python如何获取动态加载的数据呢 ?
    Python地理数据处理 24:基于arcpy批量操作汇总(七)
    亚马逊主图视频可以上传几个?有什么要求?
    DBCO-NH-(CH2)4COOH, CAS:2375193-74-9
    大模型的规模扩展是否可持续?
    在VMD上可视化hdf5格式的分子轨迹文件
    JVM 对象的访问方式
    rust学习——操作字符串、字符串转义、操作UTF8-字符串 (操作中文字符串)
    2. Java变量
  • 原文地址:https://blog.csdn.net/qq_52606908/article/details/126229305