【SpringCloud】Ribbon源码解析

e246a1dda09849a5a89535a62441565d.png

ribbon是一个负载均衡组件,它可以将请求分散到多个服务提供者实例中,提高系统的性能和可用性。本章分析ribbon是如何实现负载均衡的

1、@LoadBalanced

消费者在引入ribbon组件后,给http客户端添加@LoadBalanced注解就能启用负载均衡功能。@LoadBalanced注解比较简单,本身没有包含什么业务逻辑,值得一提的是@Qualifier注解。我们知道@Qualifier通常和@Autowired一起使用,用来指明注入bean的名称,这样就能在众多同类型的bean中选择真正需要的bean,除此之外@Qualifier也可以不指定名称,只需要在bean的入口和出口都用@Qualifier修饰,就能建立起对应关系

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
}
@Component
@Qualifier
public class A {}public class B {// 精准注入A@Autowired@Qualifierprivate A a;
}

2、LoadBalancerAutoConfiguration

和负载均衡真正相关内容在LoadBalancerAutoConfiguration内,查看spring-cloud-common包的spring.factories文件,我们知道这是一个自动配置类

# AutoConfiguration
...
org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration,\
...

LoadBalancerAutoConfiguration注入了所有使用@LoadBalanced修饰的restTemplate,为什么加了@LoadBalanced就能引入其他其他被@LoadBalanced修饰的bean,原因就是1中提到的@Qualifier。

LoadBalancerAutoConfiguration内部还有一个loadBalancedRestTemplateInitializerDeprecated方法,这个方法会对restTemplate进行了定制化处理

@LoadBalanced
@Autowired(required = false
)
private List<RestTemplate> restTemplates = Collections.emptyList();@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {return () -> {restTemplateCustomizers.ifAvailable((customizers) -> {Iterator var2 = this.restTemplates.iterator();while(var2.hasNext()) {RestTemplate restTemplate = (RestTemplate)var2.next();Iterator var4 = customizers.iterator();while(var4.hasNext()) {RestTemplateCustomizer customizer = (RestTemplateCustomizer)var4.next();// 定制化处理customizer.customize(restTemplate);}}});};
}

RestTemplateCustomizer接口的实现类也在LoadBalancerAutoConfiguration内,对restTemplate的定制化其实就是给它添加了RetryLoadBalancerInterceptor拦截器

@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(final RetryLoadBalancerInterceptor loadBalancerInterceptor) {return (restTemplate) -> {List<ClientHttpRequestInterceptor> list = new ArrayList(restTemplate.getInterceptors());list.add(loadBalancerInterceptor);// 客户端添加拦截器restTemplate.setInterceptors(list);};
}

3、RetryLoadBalancerInterceptor

查看RetryLoadBalancerInterceptor的拦截方法,核心语句是loadBalancer.choose,也就是说服务实例的选择功能其实是由LoadBalancerClient接口实现类完成的

private final LoadBalancerClient loadBalancer;public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException {...if (serviceInstance == null) {if (LOG.isDebugEnabled()) {LOG.debug("Service instance retrieved from LoadBalancedRetryContext: was null. Reattempting service instance selection");}// 选择服务实例serviceInstance = this.loadBalancer.choose(serviceName);if (LOG.isDebugEnabled()) {LOG.debug(String.format("Selected service instance: %s", serviceInstance));}}...ClientHttpResponse response = (ClientHttpResponse)this.loadBalancer.execute(serviceName, serviceInstance, this.requestFactory.createRequest(request, body, execution));       ...
}

RibbonLoadBalancerClient是LoadBalancerClient接口实现类之一,查看它的choose方法

// 选择合适的服务实例
public ServiceInstance choose(String serviceId, Object hint) {Server server = this.getServer(this.getLoadBalancer(serviceId), hint);return server == null ? null : new RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server));
}// 选择合适的服务器
protected Server getServer(ILoadBalancer loadBalancer, Object hint) {return loadBalancer == null ? null : loadBalancer.chooseServer(hint != null ? hint : "default");
}

选择服务器的任务移交给了ILoadBalancer的实现类,如ZoneAwareLoadBalancer。ZoneAwareLoadBalancer会调用父类BaseLoadBalancer的choose方法,按照指定的策略选取服务,如轮询、加权等

public Server chooseServer(Object key) {if (this.counter == null) {this.counter = this.createCounter();}this.counter.increment();if (this.rule == null) {return null;} else {try {// 按规则选择服务return this.rule.choose(key);} catch (Exception var3) {logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", new Object[]{this.name, key, var3});return null;}}
}

再聊聊服务的来源,LoadBalancer是从哪里挑选的服务?

ZoneAwareLoadBalancer在创建时会调用父类DynamicServerListLoadBalancer的构造方法,然后通过updateListOfServers方法获取服务列表

public DynamicServerListLoadBalancer(IClientConfig clientConfig, IRule rule, IPing ping, ServerList<T> serverList, ServerListFilter<T> filter, ServerListUpdater serverListUpdater) {...this.restOfInit(clientConfig);
}void restOfInit(IClientConfig clientConfig) {...this.updateListOfServers();...
}@VisibleForTesting
public void updateListOfServers() {List<T> servers = new ArrayList();if (this.serverListImpl != null) {// 获取服务列表servers = this.serverListImpl.getUpdatedListOfServers();LOGGER.debug("List of Servers for {} obtained from Discovery client: {}", this.getIdentifier(), servers);if (this.filter != null) {servers = this.filter.getFilteredListOfServers((List)servers);LOGGER.debug("Filtered List of Servers for {} obtained from Discovery client: {}", this.getIdentifier(), servers);}}this.updateAllServerList((List)servers);
}

看到服务实例自然联想到eureka,继续跟踪getUpdatedListOfServers方法

调用链:
-> DynamicServerListLoadBalancer.updateListOfServers
-> this.serverListImpl.getUpdatedListOfServers;
-> DiscoveryEnabledNIWSServerList.obtainServersViaDiscovery
-> eurekaClient.getInstancesByVipAddress
private List<DiscoveryEnabledServer> obtainServersViaDiscovery() {...// eureka客户端拉取服务List<InstanceInfo> listOfInstanceInfo = eurekaClient.getInstancesByVipAddress(vipAddress, this.isSecure, this.targetRegion);Iterator var8 = listOfInstanceInfo.iterator();...
}

方法体中出现eureka客户端,也就是说ribbon选择的服务实例其实来自于eurka服务端,是通过eureka客户端拉取到本地的

3、总结

ribbon组件向restTemplate中添加拦截器,实现负载均衡功能增强

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

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

相关文章

压缩包怎么解压,解压压缩包不损坏文件

常见格式&#xff1a; ZIP&#xff1a;最常见的压缩文件格式之一&#xff0c;支持跨平台。RAR&#xff1a;另一种常见的压缩文件格式&#xff0c;通常压缩率比ZIP高&#xff0c;但不如ZIP普及。7Z&#xff1a;来自7-Zip的压缩格式&#xff0c;支持更高的压缩率和一些高级特性。…

手机照片数据恢复,2个技巧解决你的疑惑与困扰

手机照片是我们日常生活中记录美好瞬间的重要工具&#xff0c;然而&#xff0c;当照片存储量越来越大&#xff0c;以至于手机内存不足时&#xff0c;我们就不得不放弃一部分。照片数据恢复是否还有希望呢&#xff1f;当然啦&#xff01;本文将为你提供2个实用的技巧&#xff0c…

虚拟机配置与windows之间文件夹共享samba服务:

虚拟机配置与windows之间文件夹共享samba服务: #输入安装命令&#xff1a; 第一步: 下载samba cd /etc/ sudo apt-get install samba第二步: 配置用户 sudo smbpasswd -a 虚拟机用户名第三步: 进入配置文件配置共享文件 sudo vim /etc/samba/smb.conf末尾输入以下内容: [s…

经典递归题 扩充序列 两种做法

一道经典递归题&#xff0c;两种做法&#xff0c;常规递归做法和模拟数学规律解法 3695. 扩充序列 - AcWing题库 扩充序列 样例解释 对于样例 1&#xff0c;经过 2 次扩充&#xff0c;得到序列 [1,2,1,3,1,2,1]其第 2 个元素为 2。 对于样例 2&#xff0c;经过 3次扩充&…

对不起,AI大模型不是风口

“我们正处在全新起点&#xff0c;这是一个以大模型为核心的人工智能新时代&#xff0c;大模型改变了人工智能&#xff0c;大模型即将改变世界。”——5月26日&#xff0c;百度创始人、董事长兼CEO李彦宏先生在2023中关村论坛发表了《大模型改变世界》演讲。 李彦宏指出&#…

【SpringCloud】Hystrix源码解析

hystrix是一个微服务容错组件&#xff0c;提供了资源隔离、服务降级、服务熔断的功能。这一章重点分析hystrix的实现原理 1、服务降级 CAP原则是分布式系统的一个理论基础&#xff0c;它的三个关键属性分别是一致性、可用性和容错性。当服务实例所在服务器承受过大的压力或者受…

前端工程化09-webpack静态的模块化打包工具(未完结)

9.1、开发模式的进化历史 webpacks是一个非常非常的强大的一个工具&#xff0c;相应的这个东西的学习也是有一定的难度的&#xff0c;里边的东西非常的多&#xff0c;里面涉及到的 概念的话也是非常非常的多的。 这个东西既然非常重要&#xff0c;那么在我们前端到底处于怎样…

HCIA4.26-5.10

OSPF ——开放式最短路径优先协议 无类别链路状态IGP动态路由协议 距离矢量协议 运行距离矢量协议的路由器会周期性的泛洪自己的路由表&#xff0c;通过路由之间的交互&#xff0c;每台路由器都从相邻的路由器学习到路由条目&#xff0c;随后加载进自己的路由表中。对于网络…

Python代码分析和修复工具库之coala使用详解

概要 代码质量在软件开发中至关重要,保持代码的可读性、一致性和易维护性是每个开发者的目标。coala 是一个开源的代码分析和修复工具,旨在帮助开发者自动化代码质量检查,支持多种编程语言,包括 Python、C++、JavaScript 等。通过使用 coala,开发者可以方便地集成代码检查…

AI时代的软件工程:挑战与改变

人工智能&#xff08;AI&#xff09;正以惊人的速度改变着我们的生活和工作方式。作为与AI关系最为密切的领域之一&#xff0c;软件工程正经历着深刻的转变。 1 软件工程的演变 软件工程的起源 软件工程&#xff08;Software Engineering&#xff09;是关于如何系统化、规范化地…

input调用手机摄像头实现拍照功能vue

项目需要一个拍照功能&#xff0c;实现功能如下图所示:若使用浏览器则可以直接上传图片&#xff0c;若使用手机则调用手机摄像头拍照。 1.代码结构 <!--input标签--> <input ref"photoRef"type"file"accept"image/*"capture"envir…

基于多源数据的密码攻防领域知识图谱构建

源自&#xff1a; 信息安全与通信保密杂志社 作者&#xff1a;曹增辉 , 郭渊博 , 黄慧敏 摘 要 提高网络空间安全的密码攻防能力&#xff0c;需要形成可表示、可共享、可分析的领域知识模式和知识库。利用自顶向下的构建方法&#xff0c;并通过本体构建方法梳理密码攻防领域…

IPSec:互联网协议安全机制的深度解析与应用

目录 一、IPSec概述 二、IPSec的组成 三、IPSec的工作原理 四、IPSec的用途 IPSec&#xff08;Internet Protocol Security&#xff09;作为现代网络通信中不可或缺的安全基础设施&#xff0c;旨在为基于IP&#xff08;Internet Protocol&#xff09;的数据传输提供端到端的…

【Linux】虚拟机安装openEuler 24.03 X86_64 教程

目录 一、概述 1.1 openEuler 覆盖全场景的创新平台 1.2 系统框架 1.3 平台框架 二、安装详细步骤 一、概述 1.1 openEuler 覆盖全场景的创新平台 openEuler 已支持 x86、Arm、SW64、RISC-V、LoongArch 多处理器架构&#xff0c;逐步扩展 PowerPC 等更多芯片架构支持&…

iptables 防火墙(一)

iptables 防火墙&#xff08;一&#xff09; 一、Linux 防火墙基础防火墙分类 二、iptables 的表、链结构规则表规则链数据包过滤的匹配流程 三、编写防火墙规则iptables 的安装iptables的基本语法规则的匹配条件通用匹配隐含匹配显式匹配 四、总结 在网络安全的世界里&#xf…

XRP对接文档

XRP对接文档 技术预研 参考文档 官方文档: https://xrpl.org/list-xrp-in-your-exchange.html 官方文档: https://xrpl.org/list-xrp-as-an-exchange.html#flow-of-funds 交易所对接XRP(内容齐全, 很推荐) https://blog.csdn.net/weixin_40396076/article/details/10020207…

基于51单片机的篮球计时器Proteus仿真

文章目录 一、篮球计时器1.题目要求2.思路3.仿真图3.1 未仿真时3.2 仿真开始3.3 A队进分3.4 B队进分3.5 比赛结束 4.仿真程序4.1 主函数4.2 时间显示4.3 比分显示4.4 按键扫描 二、总结 一、篮球计时器 1.题目要求 以51单片机为核心&#xff0c;设计并制作篮球计时器 基本功…

python实现符文加、解密

在历史悠久的加密技术中&#xff0c;恺撒密码以其简单却有效的原理闻名。通过固定的字母位移&#xff0c;明文可以被转换成密文&#xff0c;而解密则是逆向操作。这种技术不仅适用于英文字母&#xff0c;还可以扩展到其他语言的字符体系&#xff0c;如日语的平假名或汉语的拼音…

医院管理系统带万字文档医院预约挂号管理系统基于spingboot和vue的前后端分离java项目java课程设计java毕业设计

文章目录 仓库管理系统一、项目演示二、项目介绍三、万字项目文档四、部分功能截图五、部分代码展示六、底部获取项目源码带万字文档&#xff08;9.9&#xffe5;带走&#xff09; 仓库管理系统 一、项目演示 医院管理系统 二、项目介绍 基于springbootvue的前后端分离医院管…

跨阻放大器

#创作灵感# 最近涉及到微电流的监测项目&#xff0c;而里面的核心就是跨阻放大器&#xff0c;所以这里做一个简单的介绍&#xff0c;后续等项目完成了&#xff0c;再做一个实例的介绍。 #正文# 跨阻放大器&#xff08;Transimpedance Amplifier, TIA&#xff09;是一种将输入电…