【SpringCloud】Eureka基于Ribbon负载均衡的调用链路流程分析

文章目录

    • 前言
    • 1.调用形式
    • 2.LoadBalancerInterceptor
    • 3.负载均衡流程分析
      • 3.1 调用流程图
      • 3.2 intercept()方法
      • 3.3 execute()方法
      • 3.4 getServer()方法
      • 3.4 子类的chooseServer()方法
      • 3.5 getLoadBalancerStats().getAvailableZones().size() <= 1
      • 3.6 父类的chooseServer()方法
      • 3.7 IRule接口下的实例
      • 3.8 最终的choose()方法—return server
      • 3.9 choose()方法内部分析
    • 4. 彩蛋

前言

微服务间相互调用的基础上,服务间的调用更多是以调用某多实例服务下的某个实例的形式。而这就需要用到负载均衡技术。对于开发者而言,只要通过@LoadBalance注解就开启了负载均衡。如此简单的操作底层究竟是什么样的,我想你也很想知道。

1.调用形式

在《SpringCloud集成Eureka并实现负载均衡》的基础之上,我们可以进行一个小小的实验,debug运行程序,通过postman发起一个请求,A服务会去远程调用B服务,debug发现发送的url为:http://user-service/user/1,毫无疑问的是,这就是A调用B的途径
在这里插入图片描述
同样地,拿到这个url我们去postman里发送请求:
在这里插入图片描述
发现请求无法发送出去,路径出了问题。观察路径中的参数user-service发现他是B服务的服务名称,那为什么在A服务里向B服务发送“服务名称-接口路径-参数”形式的请求就能够正常响应?
结合集成负载均衡的过程,这一定是Ribbon在发挥作用

2.LoadBalancerInterceptor

负载均衡的前提不是传递一个具体的url,肯定是Ribbon做了某种解析,通过服务名称得到了服务下的实例列表,从而拉取Eureka-Server中的服务注册表来将请求映射到指定的某个实例上。
结合曾经前后端分离的web开发经验,后端经常会在拦截器中拦截前端发来的请求来对请求做一些操作,比如校验、拼接、鉴权…调用方发送请求和接收方收到的请求并不一致,这其中会不会也是有一个类似于拦截器的东西拦截了请求,并且转换了请求呢?
答案是必然的,那是谁——LoadBalancerInterceptor
在这里插入图片描述
可以看到的是,他实现了ClientHttpRequestInterceptor接口,具体用法细节直接去看接口中声明的方法
直观的看出接口中声明了一个intercept()方法并且接受了HttpRequest参数来拦截了客户端的http请求,并且修改的请求体!这么一看URL更改的谜底就在此处揭晓了,那么方法底层具体是怎么实现的呢:

3.负载均衡流程分析

3.1 调用流程图

Debug源码之前先来看一下源码中的调用链路总体流程图(手图):
在这里插入图片描述
概括来看则是:拦截请求—读取服务—拉取服务列表—选择规则—返回服务实例

3.2 intercept()方法

下面我们开始Debug:
1.当发送请求使得服务间发生调用关系,调用请求会先传递到拦截器中的intercept方法,可以看到的是目前还和发送是保持一致
在这里插入图片描述
2.继续向下执行,开始解析请求,拿到了请求中的URI——通过getHost()方法拿到了主机地址(服务的名称)
在这里插入图片描述

3.3 execute()方法

3.Ribbon开始做负载均衡处理
在这里插入图片描述
4.两次步入之后进入到execute()方法内部,发现传递进来的服务名称作为服务Id进入到了getLoadBalance()方法,并且得到了一个ILoadbalance接口对象,而在该对象中封装了很多的信息:
在这里插入图片描述
这里记住服务实例id的值:host.docker.internal:8084,这就是Eureka客户端接收到的实例信息

3.4 getServer()方法

5.接口对象作为参数传递到了getServer()方法,得到了一个server对象进入到方法内部。发现与此同时传递了一个Object类型的对象用于指定服务器的规则或条件,不过到目前为止,这个参数一直都是null作为传递,即loadBalancer.chooseServer()方法采用的是‘default’的方式进行选择
在这里插入图片描述

3.4 子类的chooseServer()方法

6.再次步入到chooseServer()方法,发现是在一个名为BaseLoadBalancer类(这个类是负载均衡器的具体实现后面会具体分析)下重写的父类方法
此时:可以判断的是getLoadBalancerStats().getAvailableZones().size() <= 1为TRUE
在这里插入图片描述

3.5 getLoadBalancerStats().getAvailableZones().size() <= 1

对于表达式:getLoadBalancerStats().getAvailableZones().size() <= 1进行分析
发现在BaseLoadBalancer类中通过继承抽象类AbstractLoadBalancer并重写getLoadBalancerStats()抽象方法,获取到了一个loadbalancer统计信息集合LoadBalancerStats
在这里插入图片描述
在这里插入图片描述
而封装在LoadBalancerStats中的信息里有一个ConcurrentHashMap类型的集合属性,即

volatile Map<String, List<? extends Server>> upServerListZoneMap = new ConcurrentHashMap<String, List<? extends Server>>();

用于存储可用的服务列表,这个集合中的每个条目都代表一个区域,键是区域名称,值是该区域下可用服务器的列表。
在这里插入图片描述
后续的.getAvailableZones()方法则是获取这一属性值中所有的键,也就是可用的服务区域,并作为Set集合返回来进行判断
在这里插入图片描述
很显然,这里进一步论证getLoadBalancerStats().getAvailableZones().size() <= 1是为true的,后续就会去调用父类的chooseServer()方法

3.6 父类的chooseServer()方法

7.步入到父类的chooseServer()方法中,发现最后返回了一个Server类型的对象,这肯定就是具体的服务实例信息了。
在这里插入图片描述

3.7 IRule接口下的实例

去追踪rule变量,发现是一个IRule接口的实例,即为负载均衡提供规则的接口
在这里插入图片描述
并且此接口下有大量的规则实现,而默认的规则方式则为轮询调度
在这里插入图片描述
可是看到上图在debug时,rule变量右侧灰色显示的是rule:RandomRule@12045这是因为我通过配置IRule类型的Bean指定了负载均衡的规则:

    @Beanpublic IRule randomRule() {return new RandomRule();}

只要把他注释掉,程序就会继续去采用默认的规则即RoundRobinRule

3.8 最终的choose()方法—return server

8.了解了IRule接口的rule实例,再去看他最终调用的choose()方法。同样地步入进去,由于是默认规则,则按照流程进入到了RoundRobinRule规则实现中的choose方法(其实IRule接口下的每一个规则实现类都有choose方法)
在这里插入图片描述
实现了ILoadBalancer接口的负载均衡器对象作为参数传递到了方法中,与此同时key为default。开始为随机选择预热。

3.9 choose()方法内部分析

9.进入到while循环中,不断选择服务器,直到找到一个可用的服务器。随后会判断线程是否中断,如果中断了,则直接返回null。
在这里插入图片描述
这样的情况出现频率还是很高,由此可见,这个小设计会减少很多不必要计算,提升了程序运行的效率。
而后这是分别获取两个服务列表在这里插入图片描述
从列表中选择一个
在这里插入图片描述
兜底操作,对选择的做判断在这里插入图片描述
最后成功返回Server实例给chooseServer()方法,服务发起者发送http://user-service/user请求通过Ribbon最后轮询到了localhost:8084服务实例上

4. 彩蛋

现在有很多公司都在用Nacos替换Eureka,因为感知服务列表的变化不够敏感,感知下线服务太过迟钝,就像下面这种情况:
在这里插入图片描述
服务实例已经下线,时间大约过了一分钟,却还是把下线的服务加载到了可用服务列表里(upList),其实这并不怪Ribbon,都是Eureka的错
针对这种情况我们留个彩蛋,下次再来talk about~

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

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

相关文章

基于Spring Boot 框架的试卷自动生成系统的设计与实现

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。你想解决的问题&#xff0c;今天给大家介绍…

配置Jetson扩展头--配置CSI相机

每个Jetson开发工具包包括几个扩展头和连接器(统称为“头”): 40‑pin expansion header: 让您将Jetson开发工具包连接到现成的树莓派HATs(硬件附加在顶部),如Seeed Grove模块,SparkFun Qwiic产品等。许多引脚可以用作GPIO或“特殊功能I/O”(SFIO),如I2C, I2S等。 CSI conne…

【大连民族大学C语言CG题库练习题】——判断一个矩阵是另一个矩阵的子矩阵

【问题描述】 从标准输入中输入一个N&#xff08;N<9&#xff09;阶矩阵和一个M&#xff08;M<N&#xff09;阶矩阵&#xff0c;判断矩阵M是否是N的子矩阵&#xff0c;若是则输出M在N中的起始位置&#xff0c;若不是则输出-1。若矩阵M能与N中某一区域完全相等&#xff0…

美国网站服务器SSL证书介绍

美国网站服务器的SSL证书也是一种数字证书&#xff0c;由权威数字证书机构CA验证网站的身份后所颁发&#xff0c;可实现浏览器与网站主机之间的数据传输加密。美国网站服务器搭建的网站在安装SSL证书后会在浏览器显示安全锁标志&#xff0c;数据传输协议则从HTTP传统协议升级为…

2024年测试工程师必看系列之fiddler设置手机端抓包全套教程

fiddler设置手机端抓包 安卓手机抓包 第一步&#xff1a;配置电脑和安卓的相关设置 1、手机和fiddler位于同一个局域网内&#xff1b;首先从fiddler处获取到ip地址和端口号&#xff1a; &#xff0c;点击online&#xff0c;最后一行就是ip地址 2、路径&#xff1a;Tools》Op…

NVS 错误码对应的原因

参见文档&#xff1a;esp-idf/components/nvs_flash/include/nvs.h #define ESP_ERR_NVS_BASE 0x1100 /*!< Starting number of error codes */ #define ESP_ERR_NVS_NOT_INITIALIZED (ESP_ERR_NVS_BASE 0x01) /*!< T…

基于单片机的智能家居安保系统(论文+源码)

1.系统设计 本次基于单片机的智能家居安保系统设计&#xff0c;在功能上如下&#xff1a; 1&#xff09;以51单片机为系统控制核心&#xff1b; 2&#xff09;温度传感器、人体红外静释电、烟雾传感器来实现检测目的&#xff1b; 3&#xff09;以GSM模块辅以按键来实现远/近程…

SpringCloud微服务 【实用篇】| Eureka注册中心、Ribbon负载均衡

目录 一&#xff1a;Eureka注册中心 1. Eureka原理 2. 动手实践 ①搭建EurekaServer ②服务注册 ③服务发现 二&#xff1a;Ribbon负载均衡 1. 负载均衡原理 2. 负载均衡策略 3. 懒加载 一&#xff1a;Eureka注册中心 前面已经分析了&#xff0c;无论是SpringCloud还…

【前端学java】复习巩固-Java中的对象比较(14)

往期回顾&#xff1a; 【前端学java】JAVA开发的依赖安装与环境配置 &#xff08;0&#xff09;【前端学 java】java的基础语法&#xff08;1&#xff09;【前端学java】JAVA中的packge与import&#xff08;2&#xff09;【前端学java】面向对象编程基础-类的使用 &#xff08…

南京--ChatGPT/GPT4 科研实践应用

2023年随着OpenAI开发者大会的召开&#xff0c;最重磅更新当属GPTs&#xff0c;多模态API&#xff0c;未来自定义专属的GPT。微软创始人比尔盖茨称ChatGPT的出现有着重大历史意义&#xff0c;不亚于互联网和个人电脑的问世。360创始人周鸿祎认为未来各行各业如果不能搭上这班车…

云计算赛项容器云2023搭建

部署容器云平台[5 分] 使 用 OpenStack 私 有 云 平 台 创 建 两 台 云 主 机 &#xff0c; 云 主 机 类 型 使 用 4vCPU/12G/100G 类型&#xff0c;分别作为 Kubernetes 集群的 Master 节点和 node 节点&#xff0c; 然后完成 Kubernetes 集群的部署&#xff0c;并完成 Istio …

澳洲猫罐头真实水平如何?我家亲自喂养过的优质猫罐头推荐给大家

当我们选择猫罐头时&#xff0c;要关注它的营养配方是否完整均衡、原料是否新鲜优质以及生产工艺是否科学可靠。只有满足这三个条件的猫罐头&#xff0c;才能称得上是高品质的。 猫罐头要营养均衡&#xff0c;好的配方不能少&#xff1b;猫罐头成品要优质&#xff0c;原材料要…

WPF自定义控件介绍

在WPF中&#xff0c;自定义控件通常是指从头开始创建一个新控件或从现有控件继承并扩展其功能。自定义控件与用户控件&#xff08;User Control&#xff09;不同&#xff0c;用户控件是通过组合其他控件来构建的&#xff0c;而自定义控件通常涉及对控件的更底层的渲染和行为进行…

查询数据库DQL

DQL 查询基本语法 -- DQL :基本语法; -- 1查询指定的字段 name entrydate 并返回select name , entrydate from tb_emp;-- 2 查询 所有字段 并返回select id, username, password, name, gender, image, job, entrydate, create_time, update_time from tb_emp;-- 2 查询…

C++ 继承和派生 万字长文超详解

本文章内容来源于C课堂上的听课笔记 继承和派生基础 继承是一种概念&#xff0c;它允许一个新创建的类&#xff08;称为子类或派生类&#xff09;获取另一个已经存在的类&#xff08;称为父类或基类&#xff09;的属性和行为。这就好比是子类继承了父类的特征。想象一下&…

【文末附资料链接】2023年第十三届亚太杯数学建模竞赛(APMCM)优秀参考论文思路指导(持续更新中ing)

一、赛事介绍 数学建模作为一门跨学科的科学&#xff0c;不仅需要对数学知识的熟练掌握&#xff0c;还需要对实际问题的深刻理解和解决问题的创新思维。亚太杯数学建模竞赛旨在激发青年学子的创造力和团队协作精神&#xff0c;培养其在实际问题中运用数学方法解决现实挑战的能力…

HarmonyOS ArkTS开发语言介绍(三)

1 引言 Mozilla创造了JS&#xff0c;Microsoft创建了TS&#xff0c;Huawei进一步推出了ArkTS。 从最初的基础的逻辑交互能力&#xff0c;到具备类型系统的高效工程开发能力&#xff0c;再到融合声明式UI、多维状态管理等丰富的应用开发能力&#xff0c;共同组成了相关的演进脉…

HarmonyOS脚手架:快捷实现ArkTs中json转对象

前言 在上篇《HarmonyOS开发&#xff1a;UI开展前的阶段总结》中提到了未来的规划&#xff0c;既能让大家学会鸿蒙开发&#xff0c;也能让大家在以后的开发中如虎添翼&#xff0c;最终决定&#xff0c;便以脚手架为产出物&#xff0c;结合实际的业务需求&#xff0c;进行相关技…

分享职业技术培训类型

职业技术培训类型包括&#xff1a;Python技术应用、人工智能应机器学习、大数据分析、机器学习。 一、“Python技术应用工程师” “Python技术应用工程师”职业技术认证是由工业和信息化部教育与考试中心推出一套专业化、科学化、系统化的人才考核标准&#xff0c;涉及在互…

【前端学java】Java中的异常处理(15)完结

往期回顾&#xff1a; 【前端学java】JAVA开发的依赖安装与环境配置 &#xff08;0&#xff09;【前端学java】java的基础语法&#xff08;1&#xff09;【前端学java】JAVA中的packge与import&#xff08;2&#xff09;【前端学java】面向对象编程基础-类的使用 &#xff08;…