4-Spring cloud之搭建Ribbon负载均衡——服务器上实操(下)

news2024/11/26 7:26:21

4-Spring cloud之搭建Ribbon负载均衡——服务器上实操(下)

  • 1. 前言
    • 1.1 Ribbon负载均衡架构图
  • 2. Ribbon自带的负载均衡
    • 2.1 Ribbon自带的负载均衡算法
    • 2.2 自带负载均衡之间的切换
  • 3. Ribbon自定义负载均衡
    • 3.1 自定义Ribbon负载均衡(简单试用)
      • 3.1.1 添加自定义轮询策略配置类
      • 3.1.2 启动类添加注解@RibbonClient
      • 3.1.3 重启启动服务消费者,看效果
    • 3.2 自定义Ribbon负载均衡(自定义算法)
      • 3.2.1 首先查看Ribbon轮询策略的源码
      • 3.2.2 创建自己的轮询策略
        • 3.2.2.1 新建自定义轮询策略类
        • 3.2.2.2 启用自定义轮询策略类

1. 前言

1.1 Ribbon负载均衡架构图

  • 我们在上篇文章的基础上继续Ribbon的负载均衡,为了更清晰,再放一次架构图,如下:
    在这里插入图片描述
    关于图的更多解释,请看Ribbon负载均衡上篇。
  • 关于上篇请看下面文章,如下:
    3-Spring cloud之搭建Ribbon负载均衡——服务器上实操(上).

2. Ribbon自带的负载均衡

2.1 Ribbon自带的负载均衡算法

  • Ribbon负载均衡的规则都定义在IRule接口中,而IRule有很多不同的实现类,如下:
    在这里插入图片描述

    在这里插入图片描述

  • 简单说一下这些规则

    • RoundRobinRule:轮询策略。
    • WeightedResponseTimeRule
      • 根据平均响应时间计算服务的权重,响应时间越快服务权重越大杯选中的概率越高。刚启动时如果统计信息不足,则使用 RoundRobinRule(轮询策略),等统计信息足够,则会切换到 WeightedResponseTimeRule 策略。
    • RandomRule
      • 随机策略,即:随机选择一个可用的服务器。
    • RetryRule
      • 重试机制的选择策略
      • 先按 RoundRobinRule(轮询策略)的策略获取服务,如果获取服务失败,则在指定时间内进行重试,获取可用的服务。
    • BestAvailableRule
      • 先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务。
    • AvailabilityFilteringRule
      • 先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,还有并发的连接数量超过阈值的服务(并发连接的上限,可以由客户端的 ActiveConnectionsLimit 属性进行配置),然后对剩余的服务列表按照RoundRobinRule(轮询策略)的策略进行访问。
    • ZoneAvoidanceRule
      • 以区域可用的服务器为基础进行服务器的选择,使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。而后对zone内的多个服务做轮询策略。
      • ZoneAvoidanceRule是默认实现。基于分区下的服务器的可用性选出可用分区列表,再从可用分区列表中随机选择一个分区,采用轮询的策略选择该分区的一个服务器。
        • 详细的讲解可以参考下面的文章,很不错,如下:
          Ribbon架构篇 - ZoneAvoidanceRule.

2.2 自带负载均衡之间的切换

  • 上篇文章已经知道,Ribbon默认的策略是轮询策略,那么怎么切换成别的策略呢?只需在配置类里加几行代码即可,想用什么策略自己修改即可,如下:
        @Bean  //如果此处没有配置就是默认的轮询策略,如果有配置就取配置的策略
        public IRule getMyIRule(){
    //        return new RoundRobinRule();//轮询策略
    //        return new RandomRule();//随机策略
    //        return new RetryRule();//重试机制的选择策略
            return new WeightedResponseTimeRule();//权重策略
      //              ……
    
        }
    
    在这里插入图片描述

3. Ribbon自定义负载均衡

3.1 自定义Ribbon负载均衡(简单试用)

3.1.1 添加自定义轮询策略配置类

  • 注意:此配置类不能与主启动类同目录;
  • 这里只是为了简单演示此配置类生效问题,所以用的算法还是上面提到过的Ribbon负载的算法,如下:
    在这里插入图片描述
    package com.liu.susu.config.ribbon;
    
    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;
    
    /**
     * @Description  自定义轮询策略
     * @Author susu
     */
    @Configuration
    public class MyRibbonRule { //注意:此配置类不能与主启动类同目录
    
        @Bean
        public IRule getMyIRule(){
    
            return new RandomRule();//随机策略
    //        return new RoundRobinRule();//轮询
    
        }
    
    }
    

3.1.2 启动类添加注解@RibbonClient

  • 如下:
    //此注解用来加载自定义的ribbon负载均衡配置类MyRibbonRule.java
    @RibbonClient(name = "DOG-PROVIDER", configuration = MyRibbonRule.class)
    
    在这里插入图片描述

3.1.3 重启启动服务消费者,看效果

  • 这里就不再演示了,就是访问多点几次看看效果有没能达到。

3.2 自定义Ribbon负载均衡(自定义算法)

3.2.1 首先查看Ribbon轮询策略的源码

  • 如下:
    在这里插入图片描述
    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by FernFlower decompiler)
    //
    
    package com.netflix.loadbalancer;
    
    import com.netflix.client.config.IClientConfig;
    import java.util.List;
    import java.util.concurrent.atomic.AtomicInteger;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class RoundRobinRule extends AbstractLoadBalancerRule {
        private AtomicInteger nextServerCyclicCounter;
        private static final boolean AVAILABLE_ONLY_SERVERS = true;
        private static final boolean ALL_SERVERS = false;
        private static Logger log = LoggerFactory.getLogger(RoundRobinRule.class);
    
        public RoundRobinRule() {
            this.nextServerCyclicCounter = new AtomicInteger(0);
        }
    
        public RoundRobinRule(ILoadBalancer lb) {
            this();
            this.setLoadBalancer(lb);
        }
    
        public Server choose(ILoadBalancer lb, Object key) {
            if (lb == null) {
                log.warn("no load balancer");
                return null;
            } else {
                Server server = null;
                int count = 0;
    
                while(true) {
                    if (server == null && count++ < 10) {
                        List<Server> reachableServers = lb.getReachableServers();
                        List<Server> allServers = lb.getAllServers();
                        int upCount = reachableServers.size();
                        int serverCount = allServers.size();
                        if (upCount != 0 && serverCount != 0) {
                            int nextServerIndex = this.incrementAndGetModulo(serverCount);
                            server = (Server)allServers.get(nextServerIndex);
                            if (server == null) {
                                Thread.yield();
                            } else {
                                if (server.isAlive() && server.isReadyToServe()) {
                                    return server;
                                }
    
                                server = null;
                            }
                            continue;
                        }
    
                        log.warn("No up servers available from load balancer: " + lb);
                        return null;
                    }
    
                    if (count >= 10) {
                        log.warn("No available alive servers after 10 tries from load balancer: " + lb);
                    }
    
                    return server;
                }
            }
        }
    
        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;
        }
    
        public Server choose(Object key) {
            return this.choose(this.getLoadBalancer(), key);
        }
    
        public void initWithNiwsConfig(IClientConfig clientConfig) {
        }
    }
    
    

3.2.2 创建自己的轮询策略

3.2.2.1 新建自定义轮询策略类

  • 设计思路:
    将原来的轮询改成轮询的时候每台服务器执行两次。
  • 根据上面自带的轮询策略进行修改,主要修改代码,3处,如下:
    在这里插入图片描述
    在这里插入图片描述
  • 修改后的完整代码如下:
    package com.liu.susu.config.ribbon;
    
    import com.netflix.client.config.IClientConfig;
    import com.netflix.loadbalancer.AbstractLoadBalancerRule;
    import com.netflix.loadbalancer.ILoadBalancer;
    import com.netflix.loadbalancer.Server;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.util.List;
    import java.util.concurrent.atomic.AtomicInteger;
    
    /**
     * @Description  自定义新的轮询策略(根据源码的轮询策略修改)
     * @Author susu
     */
    public class MyRoundRobinRule extends AbstractLoadBalancerRule {
        private AtomicInteger nextServerCyclicCounter;
        private static final boolean AVAILABLE_ONLY_SERVERS = true;
        private static final boolean ALL_SERVERS = false;
        private static Logger log = LoggerFactory.getLogger(MyRoundRobinRule.class);
    
        private int exeTimes =0; //每台服务器被访问执行调用的次数
    
        public MyRoundRobinRule() {
            this.nextServerCyclicCounter = new AtomicInteger(0);
        }
    
        public MyRoundRobinRule(ILoadBalancer lb) {
            this();
            this.setLoadBalancer(lb);
        }
    
        public Server choose(ILoadBalancer lb, Object key) {
            if (lb == null) {
                log.warn("no load balancer");
                return null;
            } else {
                Server server = null;
                int count = 0;
    
                exeTimes ++;
    
                while(true) {
                    if (server == null && count++ < 10) {
                        List<Server> reachableServers = lb.getReachableServers();
                        List<Server> allServers = lb.getAllServers();
    
                        int upCount = reachableServers.size();
                        int serverCount = allServers.size();
                        if (upCount != 0 && serverCount != 0) {
    
                            int nextServerIndex = this.nextServerCyclicCounter.get();
                            if (exeTimes >= 2){
                                nextServerIndex = this.incrementAndGetModulo(serverCount);
                                exeTimes = 0;
                            }
                            server = (Server)allServers.get(nextServerIndex);
    
                            if (server == null) {
                                Thread.yield();
                            } else {
                                if (server.isAlive() && server.isReadyToServe()) {
                                    return server;
                                }
    
                                server = null;
                            }
                            continue;
                        }
    
                        log.warn("No up servers available from load balancer: " + lb);
                        return null;
                    }
    
                    if (count >= 10) {
                        log.warn("No available alive servers after 10 tries from load balancer: " + lb);
                    }
    
                    return server;
                }
            }
        }
    
        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;
        }
    
        public Server choose(Object key) {
            return this.choose(this.getLoadBalancer(), key);
        }
    
        public void initWithNiwsConfig(IClientConfig clientConfig) {
        }
    
    
    
    }
    
    

3.2.2.2 启用自定义轮询策略类

  • 如下:
    在这里插入图片描述
  • 启动,测试看效果
    在这里插入图片描述
    好了,到这里吧,具体的新轮询效果还是自己点点测试吧,我这里是可行的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/724639.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【IMX6ULL - LOGO替换】根文件系统主机名logo替换教程

1、修改linux主机的配置文件/etc/hostname里的主机名 2、重启 reboot

2023电商购物网站有哪些知名和靠谱的?

最近几年&#xff0c;人们的消费方式发生了极大的改变&#xff0c;在这种趋势之下&#xff0c;很多企业都开始着手搭建自己的网购平台&#xff0c;下面是小编盘点的国内市场上较为出名的网购平台&#xff0c;大家可以借鉴其运营模式! 1、淘宝网 在中国&#xff0c;淘宝网可以说…

推荐这10款好用的产品设计软件,轻松提效

在现代技术飞速发展的时代&#xff0c;产品设计是创新和成功的关键。本文将向您推荐10款顶级产品设计软件&#xff0c;为您的设计过程增添灵感和效率。 1、即时设计 即时设计是一个基于云的产品设计协作一体化工具&#xff0c;具有很强的功能和灵活性&#xff0c;它提供了全面…

详细解读Sui Gas运作机制和其他你不知道的细节

Sui的Gas费模型使链上交互费用变得可预测而且更低廉&#xff0c;这两个关键特征对面向全球范围内的娱乐和实用apps的基础设施十分关键。区块链的Gas费是指处理事务需要支付的价格&#xff0c;用于补偿和奖励支持网络运行的服务商。 通常&#xff0c;用户支付Gas费来执行网络上…

Webpack打包ts文件

安装依赖包&#xff1a; npm i -D webpack webpack-cli typescript ts-loader 配置webpack配置文件&#xff08;webpack.config.js&#xff09;&#xff1a; //webpack中所有的配置文件信息都得写在module.exports中 module.exports{//指定入口文件entry:./src/index.ts//指定…

terminal 终端Ctrl+Shfit+E键与搜狗输入法冲突Linux

下载完搜狗输入法后&#xff0c;发现CtrlShfitE不能在终端分屏了&#xff0c;原因是和搜狗的快捷键冲突了&#xff0c;把搜狗的禁用了或者换成其它快捷键即可 界面右上角打开搜狗拼音&#xff0c;点击属性设置 把勾去掉或者换其它快捷键

eladmin环境搭建

1、参考这里的简介、快速了解、快速开始 简介 | ELADMIN 在线文档 2、后台我用的是Idea&#xff0c;要记得安装jdk、下载maven&#xff0c;Idea中要记得核对Settings、Project Structure的jdk、maven相关配置。同时也要核对数据库配置是否是好的&#xff0c;数据库是否能连接…

不同ts文件下,提示变量名重复的问题解决

同一个目录的不同文件下使用同一个变量名称出现报错 是因为ts的文件默认是全局文件 发现即使在标签栏关闭 也无法解决&#xff0c; 可以尝试在 报错的文件上加上 export{}&#xff0c;即可完美解决

实战 |记一次简单渗透测试实战

声明&#xff1a;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;鹏组安全及文章作者不为此承担任何责任。 在进行渗透测试时&#xff0c;首先需要进行的是信…

系统分析师下午案例真题及解析(2022-2020年)

请点击↑关注、收藏&#xff0c;本博客免费为你获取精彩知识分享&#xff01;有惊喜哟&#xff01;&#xff01; 2022年案例真题 真题1 阅读以下关于软件系统分析与建模的叙述&#xff0c;在答题纸上回答问题1至问题3。 【说明】 某软件公司拟开发一套博客系统&#xf…

Java使用ClassLoader读取外部json文件

我们有时候会遇到这样一种业务场景&#xff1a;某个对象是变化的&#xff0c;在不同项目的部署中&#xff0c;可能需要更改对象中的某个属性&#xff0c;这时如果我们将该对象写在代码里&#xff0c;这样不仅寻找不便&#xff0c;部署后也不能随便修改&#xff08;修改后又要重…

9个面试模板:招聘经理的问题和指南

有效的面试让我们更好的提升招聘效率&#xff0c;招聘经理和招聘人员可以使用面试模板确保高效快捷地进行面试。 面试模板有助于构建面试流程&#xff0c;为向候选人提问和记录他们的答案创建一个一致的框架。支持不同公司自定义面试模版&#xff0c;面试模版还可以更轻松地对…

Win10开始菜单打不开怎么办?Win10开始菜单打不开解决方法

Win10开始菜单打不开怎么办&#xff1f;当用户在Win10系统上遇到开始菜单打不开的问题时&#xff0c;可能会导致无法方便地访问和运行应用程序、设置等功能&#xff0c;这时候用户可以重启一下Win10电脑的任务管理器来解决问题&#xff0c;以下就是Win10开始菜单打不开解决方法…

撕去“械字号”标签,敷尔佳靠营销还能走多远?

回顾刚刚过去的六月&#xff0c;美妆护肤板块回暖趋势继续保持。 据数据显示&#xff0c;6 月淘系、抖音合计美妆GMV同比增长约13%&#xff0c;其中&#xff0c;护肤、彩妆分别同比增长14%、11%。而据美加漾科技披露的《2023年618护肤市场大数据调研》显示&#xff0c;护肤品市…

一键安装docker及docker-compose

1、创建docker存放相关文件目录&#xff0c;该目录可自己定义。2、添加相关文件&#xff0c;可在网盘提取。其中docker-20.10.9.tgz和docker-compose为安装包&#xff0c;也可根据需要在网上下载&#xff0c;注意docker-compose安装包下载后需要改名为docker-compose。 链接&am…

【正点原子STM32连载】第五十一章 汉字显示实验 摘自【正点原子】STM32F103 战舰开发指南V1.2

1&#xff09;实验平台&#xff1a;正点原子stm32f103战舰开发板V4 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id609294757420 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html# 第五…

【Kafka】Kafka基础概念笔记

【Kafka】Kafka基础概念笔记 文章目录 【Kafka】Kafka基础概念笔记1. 两种模式1.1 点对点模式1.2 发布/订阅模式 2. 基础架构3. Topic命令行操作3.1 查看 Topic 操作3.2 创建 Topic3.3 查看所有 Topic3.4 查看 Topic 的详情3.5 修改分区数3.6 删除 Topic 4. 生产者命令行操作4.…

统一参数校验

使用注解&#xff0c;统一参数校验 我们在实际的开发过程中经常会遇到需要对参数进行校验的情况&#xff0c;比如在需要用户输入手机号的时候他是不是真的输入了一个合法的手机号&#xff0c;在需要用户输入一个邮箱的时候他是不是真的输入了一个合法的邮箱&#xff0c;用户输…

可以在手机做笔记的app哪一款比较好用?

在这个信息爆炸的时代&#xff0c;人们需要快速有效地记录和整理信息。随着智能手机的普及&#xff0c;越来越多的人选择在手机上做笔记&#xff0c;相对于纸笔记录&#xff0c;手机笔记app的好处更多。 一款优秀的笔记app可以帮助我们进行内容整理&#xff0c;我们可以将笔记…

Mysql8.0下载及安装步骤完整教程

1.首先去官网下载Mysql8.0压缩包 官网地址&#xff1a;MySQL :: Download MySQL Community Server 文件下载后解压到D盘&#xff0c;具体路径可以根据自己习惯。 我解压的具体位置&#xff1a;D:\Program Files 2.创建配置文件my.ini 在和bin同级目录创建文件 my.ini&#x…