【Spring Cloud】Ribbon负载均衡原理与实战(源码级讲解)

news2025/1/11 7:43:29

本期目录

  • 1. 负载均衡原理
    • 1.1 总体流程
    • 1.2 源码解析
  • 2. 负载均衡策略
    • 2.1 负载均衡策略继承关系
    • 2.2 负载均衡策略描述
        • 1)ZoneAvoidanceRule
        • 2)AvailabilityFilteringRule
    • 2.3 修改负载均衡策略方式
      • 1)全局修改
      • 2)局部修改
  • 3. 饥饿加载
    • 3.1 背景
    • 3.2 启用饥饿加载
    • 3.3 对比测试



1. 负载均衡原理


1.1 总体流程

  • 上一章的案例中,订单微服务 order-service 发起的远程调用 URL http://userservice/user/1 并不是一个真实的 URL 。在浏览器中无法访问该 URL 。
  • 这是因为,这个 HTTP 请求被 Ribbon 拦截,由 Ribbon 解析 URL 中的 /userservice ,根据注册服务名称前往 Eureka 的注册列表中查询这个服务名称下的所有服务实例的真实 IP 地址和端口。然后 Ribbon 根据 Eureka 返回的服务实例名单,采用某种负载均衡策略从中选取一个服务实例进行调用。

image-20221123153852592


1.2 源码解析

  • 订单微服务 OrderApplication.java 发起的 HTTP 远程调用请求,首先被 Spring Cloud 的 commons 包下的 LoadBalancerInterceptor.java 负载均衡拦截器拦截下来。

    image-20221215174721935

    LoadBalancerInterceptor.java 实现了 Spring Web 包下的ClientHttpRequestInterceptor.java 客户端 HTTP 请求拦截器接口,它拦截所有客户端的 HTTP 请求。而 RestTemplate.java 正是发起客户端 HTTP 请求,因此会被这个拦截器拦截。

    image-20221215175629828

    ClientHttpRequestInterceptor.java 接口定义了一个方法 intercept()

    @FunctionalInterface
    public interface ClientHttpRequestInterceptor {
    
       ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
             throws IOException;
    
    }
    
  • 再回来查看这个接口的实现类 LoadBalancerInterceptor.java 是如何实现 intercept() 方法的。

  • LoadBalancerInterceptor.java

    @Override
    public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
          final ClientHttpRequestExecution execution) throws IOException {
       final URI originalUri = request.getURI();
       String serviceName = originalUri.getHost();
       Assert.state(serviceName != null,
             "Request URI does not contain a valid hostname: " + originalUri);
       return this.loadBalancer.execute(serviceName,
             this.requestFactory.createRequest(request, body, execution));
    }
    

    在这个方法上打断点进行逐行 Debug 。在 Postman 中发起一个查询订单的请求 http://localhost:8080/order/101

  • 可以看到 LoadBalancerInterceptor.java 的职责是拦截 RestTemplate 发起的 HTTP 请求;然后取出这个 HTTP 请求的 URL 中的微服务名称 userservice ;最后,把截取到的微服务名称 userservice 输出给 this.loadBalancerexecute() 方法来处理。

    image-20221216092544945

    鼠标悬停在 this.loadBalancer 上可以看到,它是 RibbonLoadBalancerClient.java 的对象,到这里,我们终于见到 Ribbon 负载均衡器本体了。我们点进 this.loadBalancerexecute() 方法中去看。

  • 点击后就进入了 RibbonLoadBalancerClient.javaexecute() 方法。再点进,就进入了真正的 RibbonLoadBalancerClient.javaexecute() 方法。

    image-20221216094205716

    在这里,微服务名称被称为 serviceId ,输入到 getLoadBalancer() 方法中,此方法根据微服务名称向 Eureka 拉取服务列表,返回一个名为 DynamicServerListLoadBalancer 的动态服务器列表负载均衡器。

    image-20221216094457942

    点开查看其属性 allServerList ,两个用户微服务 UserApplication 的 IP 地址和端口赫然在列。说明此时 Ribbon 已经成功向 Eureka 拿到用户微服务的服务实例列表了。

    image-20221216094833675

    接下来,就应该在拉取到的服务列表中,采用负载均衡策略选取出一个服务实例。这就是下一行代码中 getServer() 方法做的事。我们点进这个方法查看。

    image-20221216095710409

    点进 getServer() 方法中,可以看到其调用了 chooseServer() 方法,顾名思义该方法用于选取服务实例。继续点进这个方法。

    image-20221216100129037

  • 就进入了区域感知负载均衡器 ZoneAwareLoadBalancer.javachooseServer() 方法。发现它调用了父类 BaseLoadBalancer.javachooseServer() 方法。继续点进这个方法。

    image-20221216101309561

  • 点进来 BaseLoadBalancer.java 后往下走,我们就看到了调用 rule.choose() 方法。rule 是负载均衡策略,点击 rule 属性查看其是什么类的对象。

    image-20221216102313883

    可以看到,rule 是策略接口 IRule.java 的对象。默认的负载均衡策略是 ZoneAvoidanceRule (区域回避策略,在下一节详细讲解) 。

    image-20221216102832159

    按 Ctrl + H 查看 IRule.java 接口的所有实现类。其中有我们熟悉的 RoundRobinRule 轮询策略和 RandomRule 随机策略,这都是之前在 Nginx 负载均衡策略中学过的。

    image-20221216103206706

  • 看到这里,不再深挖了,点顺序执行往回走,走回 RibbonLoadBalancerClient.javaexecute() 方法中。发现 getServer() 方法使用 ZoneAvoidanceRule 负载均衡策略选取到了端口为 8082 的用户微服务 UserApplication ,接下来就可以把之前的远程调用 URL 中的服务名称 /userservice 替换成 8082 的 IP 地址和端口号 /localhost:8082 了,去发起真实的 HTTP 远程调用请求 http://localhost:8082/user/userId

    image-20221216110119474

  • Ribbon 负载均衡源码就解析到这里。总结全流程如下图所示:

    image-20221123155421535


2. 负载均衡策略


2.1 负载均衡策略继承关系

  • Ribbon 的负载均衡策略是一个叫 IRule.java 的接口来定义的,其每个子接口都是一种策略。

image-20221123160206803

  • 上一节 Ribbon 源码中,我们聊到的默认策略是 ZoneAvoidanceRule ,就在上图的最底层右侧。初次接触这个词可能很陌生,我们不妨往上看它的爷爷 ClientConfigEnableRoundRobinRule ,顾名思义,从后面几个单词 RoundRobin 中我们也不难看出,这是轮询策略的一种,只是在轮询的基础上作了加强。那么作为孙子的 ZoneAvoidanceRule ,我们就可以大胆推测,它也是轮询策略的一种。具体看下表。

2.2 负载均衡策略描述

  • 下表中罗列了 Ribbon 中常见的负载均衡策略。

image-20221123160421634


1)ZoneAvoidanceRule

  • 其中第 4 行,就是默认策略 ZoneAvoidanceRule 。我们在配置服务注册时,是可以设置微服务的 Zone 值 ( Zone 值可以理解为一个地区代码,比如服务器机房在北京、上海、深圳等) 。设置 Zone 值后,Ribbon 作轮询时,会优先选择跟自己在同一个 Zone 内的微服务 (即就近原则) ,然后再在多个微服务实例中作轮询。
  • 因此,这个 Zone 值往往只有大厂才会设置,因为大厂需要在多地搭建机房提升容灾能力和并发能力,中小公司往往所有的服务器都在一个机房,因此没有必要配置 Zone 而是直接轮询。

2)AvailabilityFilteringRule

  • 表中第 2 行,中文名是可用性筛选策略。会排除网络环境差和并发数高的服务,在剩下的服务中去做轮询。

  • 其他策略都很好理解,一般情况下选择默认的 ZoneAvoidanceRule 即可。


2.3 修改负载均衡策略方式


1)全局修改

  • 消费者服务远程调用任何其他提供者微服务都起作用。例如,订单微服务 order-service 远程调用用户微服务 user-service 时起作用,远程调用购物车微服务时也起作用。

  • 全局修改步骤:在订单微服务 order-service 中的启动类 OrderApplication.java 定义一个新的 IRule 。

  • OrderApplication.java

    // 全局修改负载均衡策略为随机策略
    @Bean
    public IRule randomRule() {
        return new RandomRule();
    }
    

2)局部修改

  • 消费者远程调用时,只在调用某个提供者微服务时起作用。例如,局部修改负载均衡策略成 RandomRule 时,订单微服务 order-service 远程调用用户微服务 user-service 时起作用,远程调用任何其他提供者微服务不起作用 (还是默认策略) 。

  • 局部修改负载均衡策略步骤:在订单微服务 order-service 中的配置文件 application.yml 中添加 IRule 负载均衡策略。

  • application.yml

    userservice:
      ribbon:
        NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule  # 负载均衡策略
    

3. 饥饿加载


3.1 背景

  • 懒加载,又称懒汉式加载,思想与单例设计模式中的懒汉式相同。Ribbon 默认采用懒加载,即第一次访问到来时才会去创建 LoadBalanceClient ,好处是启动时间快,坏处是用户第一次访问的请求时间耗时长。
  • 饥饿加载,又称饿汉式加载 ,思想与单例设计模式中的饿汉式相同。会在项目启动时就创建,好处是降低用户第一次访问的请求耗时,坏处是服务启动时间变长。
  • 在实际企业开发中,企业是宁愿服务启动耗时长一些,也要保障用户体验的。因此我们把 Ribbon 的加载方式修改成饥饿加载。

3.2 启用饥饿加载

  • 打开订单微服务 order-service 中的配置文件 application.yml

  • application.yml

    ribbon:
      eager-load:
        enabled: true # 开启饥饿加载
        clients:
          - userservice  # 指定只对用户微服务userservice启用饥饿加载
          - xxservice	# 指定多个
    

3.3 对比测试

  • 采用懒加载,重启订单微服务 order-service 后,发送第一次请求 http://localhost:8080/order/101 。耗时要 1639 ms ,这就非常离谱了,用户能明显感知到卡顿延迟。

    image-20221216150715626

  • 修改成饿汉式加载后,重启订单微服务 order-service 后,服务一启动就作服务发现。虽然服务启动需要更长时间,但能显著缩短用户第一次访问的耗时。修改后访问耗时只需要 1639 ms , (从 550 ms 提升到 20 ms) 。

    image-20221216151018112

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

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

相关文章

使用VackBAS攻击模拟平台对抗勒索病毒

勒索病毒是一种恶意软件,它可以从一台主机直接感染到整个网络(包括服务器)并加密磁盘上的任何文件和文档,勒索软件会要求受害者缴纳赎金以取回对电脑的控制权,或取回受害者根本无从自行获取的密钥去解密文件。勒索病毒…

jsp+ssm计算机毕业设计宠物店管理系统【附源码】

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: JSPSSM mybatis Maven等等组成,B/S模式 Mave…

数论的一些小小的性质总结

gcd的一些套路: 1.设一些未知数,设gcd为k,换个角度去看问题,比如去枚举倍数 2.一堆数的gcd为1,等价于它们所有数的因子重合小于n;两个数的gcd1,它们的因子之间没有重合 3.相邻两数之间gcd1&a…

SpringMVC:SpringMVC请求映射路径(3)

SpringMvc请求路径1. 环境准备2. 问题提出3. 设置映射路径3.1 方法一:修改Controller3.2 方法二:优化路径配置1. 环境准备 项目结构 BookController类 public class BookController {RequestMapping("/save")ResponseBodypublic String save…

告别XML,Android新声明式UI框架《Jetpack Compose入门到精通》最全开发指南

什么是Jetpack Compose? Jetpack Compose是Android的新声明式UI框架。长期以来, Android 开发人员习惯于使用带有状态视图的xml编写UI,这些状态视图通过逐步浏览视图层次结构进行更新。使用Jetpack Compose, UI 是通过使用KotinQ 函数以无状态方式编写的。 可组合函数使用注…

大一学生HTML期末作业 【html体育排球5页面带注册】学生网页设计作业源码

🎉精彩专栏推荐 💭文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 💂 作者主页: 【主页——🚀获取更多优质源码】 🎓 web前端期末大作业: 【📚毕设项目精品实战案例 (10…

RT-Thread Studio创建STM32WB55工程

STM32WB是ST推出的物联网标准无线连接SoC芯片,可支持BLE、ZigBee等标准协议,内置M4F和M0双内核,其中M0主要运行底层协议栈,而M4F则可以用于应用的开发。 RT-Thread是国内目前比较成熟、比较成熟的物联网操作系统了,有…

C++ Reference: Standard C++ Library reference: Containers: map: map: crend

C官网参考链接&#xff1a;https://cplusplus.com/reference/map/map/crend/ 公有成员函数 <map> std::map::crend const_reverse_iterator crend() const noexcept;返回指向反向结束的const_reverse_iterator 返回一个const_reverse_iterator&#xff0c;指向容器中第…

CentOS 8 桌面版右上角网络图标消失的解决办法

我们在手动修改网络连接的配置文件后&#xff0c;桌面右上角的网络连接图标可能会消失。 正常显示的网络图标&#xff1a; 网络图标消失后的样子&#xff1a; CentOS 的网络连接由网络管理工具 NetworkManager 负责&#xff0c; 这个问题多半与其有关。 可能的原因 1&#xf…

音视频Media内核学习——OpenMax浅析

一、OpenMax简介&#xff08;缩写为&#xff1a;OMX&#xff09; OpenMAX是一个多媒体应用程序的标准。由NVIDIA公司和Khronos™在2006年推出。 它是无授权费的、跨平台的C语言程序接口序列&#xff0c;这些接口对音频、视频、静态图片的常用操作进行封装。 它包括三层&…

[激光原理与应用-57]:激光器 - 光学 - 常见光学镜片介绍

目录 第1章 光学镜片和普通镜片 1.1 光学镜片和普通镜片的区别 1.2 什么是光学镜片 1.3 反射镜 1.4 透镜 1.5 镜片镀膜 第2章 光学镜片的类型 2.1 半透镜 2.2 半透半反反射镜 - 分束镜 2.3 凸透镜 2.4 凹透镜 2.5 准直镜 2.6 偏振镜片 2.7 分色镜与分色反射镜 2…

【SAP ABAP】SAP Webservice RESTful 接口服务发布教程

SAP Webservice & RESTful 接口服务发布教程1、SAP Webservice 类型2、SAP Webservice 服务发布2.1、准备 RFC2.2、通过 RFC 创建服务2.3、查看 WSDL2.4、访问服务2.5、删除服务3、SAP RESTful 服务发布3.1、创建数据服务类3.2、维护服务3.3、访问服务3.4、删除服务4、SAP …

Ajax(五) Ajax加强

1. 模板引擎的实现原理 1.1 正则与字符串操作 exec() 函数用于检索字符串中的正则表达式的匹配。 如果字符串中有匹配的值&#xff0c;则返回该匹配值&#xff0c;否则返回 null。 1.基本语法&#xff1a;正则表达式 2.分组 正则表达式中 ( ) 包起来的内容表示一个分组&#…

【AIOT】QT样式QSS

使用桌面的PyQt或者web的flaskweb方便快捷的部署搭建可视化AI应用演示Demo&#xff0c;这里记录使用PyQt搭建基于Mediapipe和MixMLP网络的识别控制系统QSS样式代码。 Styles sheets are textual specifications that can be set on the whole application using QApplication::…

基于MOdel的自治交通模拟框架,用于故障-错误-故障链分析(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

二叠氮聚乙二醇,N3-PEG-N3,点击化学试剂简介 CAS 82055-94-5, Azide-PEG-Azide双边活性PEG衍生物

名称 二叠氮聚乙二醇 N3-PEG-N3 中文名称 叠氮PEG叠氮 聚乙二醇二叠氮 二叠氮聚乙二醇 英文名称 N3-PEG-N3 Azide-PEG-Azide CAS 82055-94-5 溶剂 溶于水和大部分有机溶剂 存储条件 -20读冷冻保存&#xff0c;惰性气体保护 N3-PEG-N3是一种双边活性PEG衍生物&#xff0c;可…

Ubuntu服务器Docker及常用库件安装

wshanshi&#xff1a;嗯…是从有道云笔记里弄出来的… 一、安装步骤 1.1、 检查并卸载已安装的docker $ sudo apt-get remove docker docker-engine docker.io containerd runc1.2、使用存储库安装 $ sudo apt-get update$ sudo apt-get install \apt-transport-https \ca-c…

[SCTF2019]Flag Shop (RUBY模板注入)

打开界面发现一个通过金钱来获得flag的&#xff0c;然后点击work或增加金钱但都是个位数 首先想了一下如果做一个脚本一直点击work不就好了吗&#xff0c;但是又想了一下服务器响应太快也不行&#xff0c;如果设置sleep那时间太长了 然后换一个思路&#xff0c;burp抓包看了一…

网络技术基础测试(一)

在一般布线中双绞线最长不可超过&#xff1a;100米网络拓扑图中路由器的图形为&#xff1a; Pv4地址由哪俩部分组成&#xff1a;网段地址和主机地址查询DNS域名信息的CMD命令为&#xff1a;NSLOOKUP关于局域网交换机&#xff0c;描述错误的是&#xff1a;用户可以有不同权限某…

Linux 性能分析工具大全

出于对Linux操作系统的兴趣&#xff0c;以及对底层知识的强烈欲望&#xff0c;因此整理了这篇文章。本文也可以作为检验基础知识的指标&#xff0c;另外文章涵盖了一个系统的方方面面。如果没有完善的计算机系统知识&#xff0c;网络知识和操作系统知识&#xff0c;文档中的工具…