Feign与SpringCloud LoadBalancer实现负载均衡源码分析

news/2025/3/25 2:32:55/文章来源:https://www.cnblogs.com/LiuFqiang/p/18675438

SpringCloud LoadBalancer

众所周知,SpringCloud体系中负载均衡的组件有SpringCloud LoadBalancer和Ribbon,Ribbon也在逐渐的被替代掉,因为SpringCloud LoadBalancer性能更高,支持响应式
下面通过hard-coded体现一下SpringCloud的负载均衡
首先有一个【say-hello】服务,提供"/","/greeting"接口,同时为了后续观测方便,将此服务的端口号也返回

我们的调用方【user】服务,使用webflux,下面为主要依赖

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>
<dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>2023.0.0</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>

想要实现负载均衡,首先需要WebClient发起请求并且添加ReactorLoadBalancerExchangeFilterFunction过滤器,在使用的地方注入ReactorLoadBalancerExchangeFilterFunction即可,

另外还需要提供ServiceInstanceListSupplier,并且注入为bean,稍后再分析原理,,这里serverId为say-hello,我们将服务实例写成固定的单个节点,8081,8082,8082

现在启动say-hello服务的8081,8082,8083服务来体现负载均衡

调整user服务的日志等级为debug

logging:level:root: debug

访问user服务的/hello接口

可以明显的发现当前的负载策略是依次轮询,并且每次起始的实例并非8081
实现原理也很简单,主要在WebClient调用的时候会首先执行ExchangeFilterFunction的filter方法,ExchangeFilterFunction的andThan可以实现无限套娃,相当于过滤器的链式调用,有点绕

filterFunctions为自己传入的filter,andThan其实相当于next,我们在/hello接口中传入的filter为ReactorLoadBalancerExchangeFilterFunction,其中负载均衡主要在这里面进行开展,也可以传入自定义的过滤器
LoadBalancerLifecycle将获取当前NamedContextFactory,并且它确保负载均衡器可以在整个生命周期正常工作,也可以做一些额外的工作,
比如可以记录日志

也可以使用MicrometerStatsLoadBalancerLifecycle记录一些指标信息
接着调用LoadBalancerLifecycle的start方法
下面会调用主要逻辑choose方法
在LoadBalancerClientConfiguration,如果我们没有定义的话会默认使用RoundRobinLoadBalancer,采用依次轮询的策略,

而像其他的ReactorLoadBalancer都需要ServiceInstanceListSupplier来提供实例的一些信息,像在这个demo中我们使用固定值

根据这些扩展接口,我们很容易的来集成其他的注册发现框架,比如nacos通过DiscoveryClientServiceInstanceListSupplier
获取完ServiceInstance,我们来看RoundRobinLoadBalancer的轮询算法实现

其中position为初始化时产生的[0,999]的随机数,每次调用都会进行+1并且与Integer.MAX_VALUE进行与运算,如果是正整数,因为Integer.MAX_VALUE是2^32 -1 。0111 1111 1111 1111 1111 1111 1111 1111,当执行Integer.MAX_VALUE + 1时
会导致最高位(符号位)发生变化,从而产生溢出,加1后的结果为 1000 0000 0000 0000 0000 0000 0000 0000,表示的是最小的负数,即Integer.MIN_VALUE,次数再和Integer.MAX_VALUE进行与运算,所以pos的取值范围为[0, Integer.MAX_VALUE]
当连续的整数对相同的数取余时,余数也是连续的,所以就实现了依次轮询的策略
SpringCloud LoadBalancer里面内置了RandomLoadBalancer随机算法,实现应该是最简单的,直接使用随机数ThreadLocalRandom.current()
当然,我们也可以自己实现负载均衡的策略,比如下面是按照权重来实现,
修改DemoServiceInstanceListSuppler中的DefaultServiceInstance,在metadata添加额外参数weight,instance1权重为1,instance2权重为2,instance3权重为3

在当前NamedContext添加ReactorLoadBalancer bean

@Beanpublic ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(ServiceInstanceListSupplier serviceInstanceListSupplier) {return new ReactorServiceInstanceLoadBalancer() {@Overridepublic Mono<Response<ServiceInstance>> choose(Request request) {return serviceInstanceListSupplier.get(request).next().map(instances -> {return getInstanceResponse(instances);});}private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {if (instances.size() == 1) {return new DefaultResponse(instances.get(0));}int totalWeight = instances.stream().mapToInt(this::getWeight).sum();Random random = new Random();int r = random.nextInt(totalWeight);for (ServiceInstance instance : instances) {int weight = getWeight(instance);if (r < weight) {return new DefaultResponse(instance);}r -= weight;}return new EmptyResponse();};private int getWeight(ServiceInstance instance) {// 从元数据中获取权重,默认权重为 1String weightStr = instance.getMetadata().getOrDefault("weight", "1");try {return Integer.parseInt(weightStr);} catch (NumberFormatException e) {return 1; // 如果解析失败,默认权重为 1}}};}


重启项目,可以看到节点大概是按照我们预设的权重来的,instance1 8081端口的几率还是很小的

除了上面手动往WebClient里面添加Filter的方法之外,我们更多的是使用自动配置的方式,以减少程序的复杂性,
新添加bean,并且添加注解@LoadBalancerClient,name为say-hello,

新建接口/hi


其中@LoadBalancerClient会通过LoadBalancerClientConfigurationRegistrar注入为NamedContextFactory.Specification,如果添加了@LoadBalanced注解将在BeanPostProcessor的时候将会添加ExchangeFilterFunction

参考文档
https://spring.io/guides/gs/spring-cloud-loadbalancer

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

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

相关文章

JS — 判断语句与循环语句

js的判断语句与循环语句...(* ̄0 ̄)ノ判断语句JavaScript中的if-else语句与C++、Python、Java中类似。直接输出到控制台:test.html中的内容为: <script type="module">let score = 90;if (score >= 85) {console.log("A");} else if (score &g…

Living-Dream 系列笔记 第92期

最小路径点覆盖 在一张 DAG 上,求一个路径的集合,使得它们两两不相交,且覆盖所有的点。 结论:答案即为 \(总点数-最大匹配\)(于是 \(总点数-最大匹配=总点数-最小点覆盖=最大独立集=最大团=最小路径点覆盖\))。 证明: 不妨转换角度,从研究路径转为研究点。 因为路径两两…

毕设学习第四天之Java的注解和反射

注解(Annotation) Java 注解(Annotation)是一种特殊的语言构造,用于为代码元素(如类、方法、字段等)提供元数据,通常不直接影响程序的逻辑执行。它们可以被编译器、框架或工具解析,用于执行特定操作,如自动化配置、代码生成、验证等。Java 提供了内置的注解(如 @Overr…

Docker安装wikijs wiki系统.210818

1. 拉取mysql8的镜像并运行 docker pull mysqldocker run -d -v /data/mysql/data:/var/lib/mysql -v /data/mysql/conf:/etc/mysql/conf.d --name mysql -e TZ=Asia/Shanghai -e MYSQL\_ROOT\_PASSWORD=1234 -p 3306:3306 mysql:latest2. 进入mysql,创建并修改权限 docker…

重载自动驾驶平板车HAV

随着无人驾驶在封闭场地和干线道路场景的加速落地,港口作为无人化运营的先行者,其场景的复杂度、特殊性对无人化运营的技术提出了各种挑战。为了应对港口无人化运营在实质化落地过程的挑战,经纬恒润借助自身在无人驾驶领域的深厚积累与实践,研发了全新的第三代重载自动驾驶…

【深度学习教程】Python 如何用 LSTM 做情感分析?小白也能上手!

Hello 大家好,今天我们来聊一个超热门的话题——**LSTM 网络在情感分析中的应用**!想象一下,通过深度学习,你的代码可以读懂人类情绪,知道“我爱你”和“我讨厌你”的区别,是不是很酷?今天这篇文章,我会手把手教你从零开始,用 Python 和 Keras 实现一个**基于 LSTM 的…

安川YASKAWA机器人主板维修方法合集

安川机械手板卡故障分析与YASKAWA机械臂主板维修步骤 1. 确认故障现象:首先,我们需要详细了解安川机器人主板故障现象,包括但不限于工作异常、运行错误、速度变慢等。 2. 拆卸主板:根据故障现象,找到相应的机械手电路板故障部位,并小心地将主板拆卸下来,确保不损坏其他部…

lstm理解

batch_size:表示再这样的数据集中有多少数据表单,本列中为3张表单,构成3维数据。若是10张表单,则10张表单堆叠在一起,构成3维数据。time_step:表示在3维时间序列中,每张表有多少行,每个时间序列有多少点,时间点实际就是时序序列的序列长度,成为时间步。input_diensio…

虚拟机Centos7.6安装Mysql8

由于本人贫穷, 没钱搞服务器, 就在虚拟机上安装了一个centos7.6服务器,然后今天给大家带来的是在centos7.6安装mysql8的教程。如果你也跟我一样贫穷,可以根据下面这篇教程来在虚拟机上安装centos7.6系统: https://zhuanlan.zhihu.com/p/698840895安装完成后,用xshell等工…

Cisco ACI Simulator 6.1(2g) - ACI 模拟器

Cisco ACI Simulator 6.1(2g) - ACI 模拟器Cisco ACI Simulator 6.1(2g) - ACI 模拟器 Application Centric Infrastructure (ACI) Simulator Software 请访问原文链接:https://sysin.org/blog/cisco-acisim-6/ 查看最新版。原创作品,转载请保留出处。 作者主页:sysin.orgAC…

如何让项目进度一目了然?办公可视化工具的最佳实践

在数字化办公浪潮中,信息的快速流转与精准解读成为提升竞争力的关键要素。办公可视化工具应运而生,它宛如一座桥梁,跨越了数据的繁杂海洋,将晦涩难懂的数据转化为直观易懂的视觉呈现。 从项目管理角度来看,可视化工具能够将项目进度、任务分配等关键信息以清晰的图表、看板…

docker安装apache.211011

1, docker下载apache docker search apache docker pull httpd docker images2,docker run docker run --name httpd -p 8081:80 -v /ZT/webnav/:/usr/local/apache2/htdocs -d httpd`重要提示: apache默认为80端口,所以如果,如果,如果需要改80端口为其他端口,切记!!!…