详解Ribbon

news2024/11/19 15:57:44

目录

1.概述

2.使用

2.1.引入

2.2.启用

2.3.切换负载均衡算法

3.负载均衡源码分析

3.1.接口

3.2.抽象类

3.3.选择服务器

3.4.原子性

4.自定义负载均衡算法


1.概述

Ribbon是Netflix开源的一个客户端负载均衡库,也是Spring Cloud Netflix项目的核心组件之一。它主要用于在微服务架构中对服务进行负载均衡,以提高系统的可用性和性能。ribbon不是通信组件,而是服务调用者和通信组件之间的中间层,主要就是用来做负载均衡,选择出适合处理本次请求的服务节点。

现在整个spring cloud体系中的通信组件其实就是封装了负载均衡组件+HTTP通信组件,HTTP通信组件没什么好说的,就是用来发起HTTP请求的,市面上的HTTP通信组件也很多,诸如spring boot自带的RestTemplate,apache的Apache HttpClient等等。值得去探究一下的是负载均衡组件,其作为负载均很组件决定了请求的分发,可以说是整个通信组件的核心。

从Spring Cloud 2020.0版本开始,Spring Cloud官方已经将Ribbon标记为过时(deprecated),推荐使用Spring Cloud LoadBalancer作为替代方案。这样做是基于标准化的考虑,整个spring生态历来都是希望“包容万物”,所以社区自然不希望在负载均衡组件上直接就采用一个固定的实现,而是希望能让三方的解决方案可以平滑的接入、切换。

虽然ribbon以后不再是负载均衡组件的首选,但是作为最经典的负载均衡组件,其底层的一些思想仍然被后面的方案沿用,其实看明白ribbon的源码基本上也就明白负载均衡的原理了,万变不离其宗。

2.使用

2.1.引入

博主的上篇文章详细介绍了怎么使用eureka+通信组件来完成服务的注册、调用,其中也详细的介绍了ribbon的使用,可以移步:

详解Eureka服务注册和调用__BugMan的博客-CSDN博客

总的来说就是:

eureka集成了ribbon,导入eureka后不用单独导入ribbon,但是要注意的是一定要选对版本号,不要选到一个已经把ribbon移除的高版本,本文使用的依赖版本:

当然你也可以直接降级整个spring cloud的版本号,关于spring cloud版本号的问题,可以移步博主的另一篇文章,会有详细讲解:

详解Spring Cloud版本问题__BugMan的博客-CSDN博客

2.2.启用

引入依赖后在承载HTTP通信组件上开启负载均衡即可,此处以spring boot自带的RestTemplate为例,这样在每次客户端(消费者)发起http请求的时候都会在本端进行负载均衡运算后再进行服务访问。

2.3.切换负载均衡算法

负载均衡的核心接口Irule有多个实现类,每个实现类实现不同的负载均衡算法,

常用的有,轮询、随机、可获得、重试等几种:

  • RoundRobinRule,轮询

  • RandomRule,随机

  • AvailabilityFilteringRule,会过滤掉,跳闸,访问故障的服务,对剩下的进行轮询

  • RetryRule,会按照轮询获取服务,如果服务获取失败,则会在指定的时间内进行重试

  • 需要切换的时候直接在@Configuration中注入@Bean即可:

3.负载均衡源码分析

3.1.接口

IRule接口:

  • choose:选举出一个服务器
  • get/setLoadBalancer:获取、修改均衡器

ILoadBalancer:

与服务器打交道,负责寻找、登记服务器

3.2.抽象类

AbstractLoadBalancer实现了Irule接口,重写了均衡器的get/set方法,只留下一个抽象方法——choose,待子类重写。

3.3.选择服务器

所有实现类都继承抽象类AbstractLoadBalancer。各自去重写choose方法,即各自实现不同的负载均衡规则(此处以ribbon默认的负载均衡规则,RoundRobinRule为例):

choose方法即负载均衡策略,是各负载均衡类的核心方法(此处以ribbon默认的负载均衡规则,RoundRobinRule为例):

均衡器会和注册中心交互,然后记录下当前整个系统中所有服务器的相关信息,包含服务器总数,可用总数等。

向均衡器所要服务器总数、服务器可用总数,然后根据这两个值进行运算,挑选出承载该此流量的服务器。

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;
            }
        }
    }

整个过程中封装服务器相关信息的Server类,其中有服务器的详细参数:

 

3.4.原子性

挑选过程中,为了保证原子性,使用了自旋锁(CAS),保证每次处理的只有一个访问线程,其余线程处于自选等待状态:

compareAndSet(期望值,修改值)

期望值,即版本号。

修改值,即要将版本号更新为的值。

判断期望值是否改变(前后是否相同),如果期望值未改变,则将期望值更新为修改值。

返回true,否则返回false。

4.自定义负载均衡算法

存在顶级接口并且可以切换负载均衡算法,那自然可以自定义负载均衡算法,以下是一个根据服务器权重进行负载均衡的一个负载均衡算法:

public class CustomWeightedRandomRule extends AbstractLoadBalancerRule {
    private AtomicInteger totalWeight = new AtomicInteger(0);

    @Override
    public Server choose(Object key) {
        ILoadBalancer lb = getLoadBalancer();
        if (lb == null) {
            return null;
        }

        List<Server> allServers = lb.getAllServers();
        int serverCount = allServers.size();
        if (serverCount == 0) {
            return null;
        }

        int randomWeight = ThreadLocalRandom.current().nextInt(totalWeight.get());
        int currentWeight = 0;

        for (Server server : allServers) {
            currentWeight += getWeight(server);
            if (randomWeight < currentWeight) {
                return server;
            }
        }

        // Fallback to the default server if no server is selected
        return super.choose(key);
    }

    private int getWeight(Server server) {
        // Return the weight of the server (custom logic)
        // Example: return server.getMetadata().getWeight();
        return 1; // Default weight is 1
    }

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
        super.initWithNiwsConfig(clientConfig);
        // Calculate the total weight of all servers
        List<Server> allServers = getLoadBalancer().getAllServers();
        totalWeight.set(allServers.stream().mapToInt(this::getWeight).sum());
    }
}

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

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

相关文章

常见网络服务器并发模型

近些年&#xff0c;随着互联网的大发展&#xff0c;高并发服务器技术也快速进步&#xff0c;从简单的循环服务器模型处理少量网络并发请求&#xff0c;演进到解决C10K&#xff0c;C10M问题的高并发服务器模型。本文主要以TCP为例&#xff0c;总结了几种常见的网络服务器模型的实…

巧用文件批量改名高手删除子文件夹一例

比如有很多商品文件夹&#xff0c;里面又分出主图、细节图等&#xff0c;现在因工作需要把主图、细节图这些子文件夹去掉&#xff0c;把子文件夹里面的文件放在商品名称的父文件夹中&#xff0c;如图&#xff1a; 打开主图文件夹&#xff0c;我们可以看到文件名结构为数字编号的…

Git学习 - 2023-06-08

2023暑期学习 Git基础Git Fetch VS Git Pullgit pull --rebase VS git pull几种merge的方法Fork VS Clone CS Branch如何把master的内容更新到分支上详尽介绍 git fetch VS git pull其他命令 Git基础 git branch branch-name # 创建一个新的分支git checkout branch-name # 切…

Golang | Web开发之Gin框架快速入门基础实践

欢迎关注「全栈工程师修炼指南」公众号 点击 &#x1f447; 下方卡片 即可关注我哟! 设为「星标⭐」每天带你 基础入门 到 进阶实践 再到 放弃学习&#xff01; 专注 企业运维实践、网络安全、系统运维、应用开发、物联网实战、全栈文章 等知识分享 “ 花开堪折直须折&#xf…

Learning C++ No.30 【lambda表达式实战】

引言&#xff1a; 北京时间&#xff1a;2023/6/9/9:13&#xff0c;今天8:15起床&#xff0c;可能是最近课非常少&#xff0c;导致写博客没什么压力&#xff0c;什么时间都能写&#xff0c;导致7点起不来&#xff0c;哈哈哈&#xff0c;习惯睡懒觉了&#xff0c;但是问题不大&a…

【二十七】springboot之通过threadLocal+参数解析器实现同session一样保存当前登录信息的功能

springboot篇章整体栏目&#xff1a; 【一】springboot整合swagger&#xff08;超详细 【二】springboot整合swagger&#xff08;自定义&#xff09;&#xff08;超详细&#xff09; 【三】springboot整合token&#xff08;超详细&#xff09; 【四】springboot整合mybatis…

绿豆影视系统5.1.8反编译版源码:PC+WAP+APP端【附搭建教程+软件】

简介&#xff1a; 绿豆影视系统5.1.8反编译版源码&#xff1a;PCWAPAPP端【附搭建教程软件】 优化内容 1.专题类目&#xff0c;在后台进行设置 2.短视频类目 &#xff0c;需要有信天翁id 3.优化首页栏目不显示问题 4.去除我的页面 不常用功能 5.修复自定义密码只能输入数字的…

二阳竟然是这样的~

今天周六&#xff0c;家人都出去玩了&#xff0c;把我自己扔家里了&#xff0c;因为我2阳了&#xff0c;出门都不带我玩了。 正好趁这个时间简单写下2阳的症状&#xff0c;和1阳有什么不一样。 先说结论&#xff1a; 我的亲身感受是2阳比1阳轻的多&#xff0c;没有浑身关节疼&a…

MySQL-索引详解(三)

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a;小刘主页 ♥️每天分享云计算网络运维课堂笔记&#xff0c;努力不一定有回报&#xff0c;但一定会有收获加油&#xff01;一起努力&#xff0c;共赴美好人生&#xff01; ♥️树高千尺&#xff0c;落叶归根人生不易&…

第64篇:史上最严重的APT供应链攻击事件,借助Solarwinds攻击欧美的流程图梳理和分析(上篇)...

Part1 前言 大家好&#xff0c;我是ABC_123&#xff0c;公众号正式更名为”希潭实验室”&#xff0c;敬请关注。本期分享一个堪称史上影响最大、危害最大的供应链攻击APT案例——Solarwinds供应链攻击事件&#xff0c;SolarWinds的旗下有数万家客户公司&#xff0c;包括了”财…

h.264 h.265 协议基本概念记录

区分一些概念 MPEG-4 是一套用于音频、视频信息的压缩编码标准H.264&#xff0c;AVC&#xff0c;编码格式&#xff0c;是MPEG-4 的第10部分H.265&#xff0c;HEVC&#xff0c;编码格式&#xff0c;是MPEG-H的第2部分mp4&#xff0c;rmvb&#xff0c;mkv&#xff0c;avi是容器&…

【ChatGPT】数据科学 ChatGPT Cheat Sheet 书籍分享(阿里云盘下载)

封皮 以下为书中部分内容的机器翻译 我们的重要提示指南 1. 以 AI 角色的描述开始提示。 例如&#xff0c;“你是{x}”或“我希望你扮演{x}”。如果您不确定&#xff0c;请尝试“你是一个有帮助的助手”。 例如&#xff0c;您是 OpenAI 的数据科学家&#xff0c;您正在研究大型…

测量项目总结

和朋友合作开发一个测量机产品, 用于测量汽车零件形位公差, 客户的客户是电动汽车第一品牌, 我负责上位机开发, 历时2个月, 完成上百次的commit. 时间虽紧, 但代码质量上没有妥协, 软件层次划分合理, 后续考虑做成系列产品. 开发利器 感恩这个时代, 现在的软件开发开发体验真好…

git hook

hook hook 翻译为钩子&#xff0c;简单说就是监听某个事件&#xff08;操作&#xff09;&#xff0c;然后触发自定义逻辑 在 git 中可以监听 commit&#xff0c;push 等操作&#xff0c;在操作之前或之后触发对应的 hook&#xff0c;在 hook 中写自定义的逻辑&#xff0c;比如…

nginx扩展篇之nginx.conf 详细文档

nginx.conf 配置文件 基本说明 Nginx 的配置文件位置 文件位置 ​ 安装目录\conf\nginx.conf ​ 安装目录\nginx.conf 两个文件是一样的 多说一句&#xff1a;使用/usr/local/nginx/sbin/nginx 启动Nginx &#xff0c;默认用的是安装目录\nginx.conf 配置文件 作用&…

网络安全学术顶会——SP 2023 议题清单、摘要与总结(上)

总结 本文总结了196篇近期涉及网络安全领域的研究论文。主要可分为以下几类: 隐私保护,涉及到匿名认证、隐私保护机器学习等机器学习安全,主要研究对抗样本和隐蔽后门等问题浏览器和网络安全,涉及指纹识别、端到端加密、网站选择标志等嵌入式系统安全,主要针对 IOT 安全操作系统…

java并发编程:LinkedBlockingQueue详解

文章目录 简介源码分析属性构造函数入队方法put(E e)offer(E e)offer(E e, long timeout, TimeUnit unit) 出队方法take()poll()获取元素方法删除元素方法 问题总结 简介 在集合框架里&#xff0c;想必大家都用过ArrayList和LinkedList&#xff0c;也经常在面试中问到他们之间…

光线追踪RayTracing,基本原理,判断物体与光线相交

光线的三点假设&#xff1a; 光线按直线传播光线之间不会发生碰撞光线会经过一系列折射反射进入摄像机 可以从摄像机发出光线&#xff0c;推出可逆的光路 上图中&#xff0c;透明球在与相机直连的线条处&#xff0c;需要将折射和反射的着色点结果相加&#xff0c;如果有光源直…

Neuroimage | LMDA-Net第一作者亲自讲述其设计思想

近期&#xff0c; 天津大学精仪学院和医工院联合&#xff0c;在神经科学和神经成像顶刊 Neuroimage中发表题为《LMDA-Net: 一种具有通用性和可解释性的轻量级EEG解码网络》的学术论文, 为解决人工神经网络模型在EEG解码时面临的跨数据集泛化性差、预测波动性高和模型可解释性差…

【2023】Redis cluster集群模式搭建

目录 1.cluster集群介绍2.搭建cluster集群2.1.架构图2.2.搭建集群2.2.1.创建所需配置文件2.2.2.创建集群所需容器2.2.3.创建集群&#xff1a;master1节点连接其他节点2.2.4.配置从节点&#xff0c;完成三主三从 3.在cluster集群内读写数据 1.cluster集群介绍 Redis Cluster是R…