微服务流量分发核心:Spring Cloud 负载均衡解析

目录

理解负载均衡

负载均衡的实现方式

服务端负载均衡

客户端负载均衡

Spring Cloud LoadBalancer快速上手

常见的负载均衡策略

自定义负载均衡策略

LoadBalancer 原理

理解负载均衡

在 Spring Cloud 微服务架构中,负载均衡(Load Balance)是实现服务高可用、提高系统吞吐量的核心机制之一。它通过将请求合理分发到多个服务实例,避免单个实例过载,同时实现故障自动隔离,是服务调用链路中的关键环节。

在微服务中,一个服务通常会部署多个实例(如产品信息服务可能有product-service:9090product-service:9091product-service:9092等)。负载均衡的核心目标是:

  1. 请求分发:将服务消费者的请求均匀分配到多个服务提供者实例,避免单点压力过大。

  2. 故障隔离:自动排除不可用的实例(如宕机、健康检查失败),确保请求只发送到可用实例。

  3. 弹性伸缩支持:当服务实例扩缩容时,能自动感知并调整分发策略,无需人工干预。

负载均衡的实现方式

负载均衡分为服务端负载均衡客户端负载均衡

服务端负载均衡

比较有名的服务端负载均衡器是Nginx,请求先到达Nginx负载均衡器,然后通过负载均衡算法,在多个服务器之间选择⼀个进行访问。

客户端负载均衡

把负载均衡的功能以库的方式集成到客户端,而不再是由⼀台指定的负载均衡设备集中提供。

比如Spring Cloud的Ribbon,请求发送到客户端,客户端从注册中心(比如Eureka)获取服务列表,在发送请求前通过负载均衡算法选择⼀个服务器,然后进行访问。

Ribbon是Spring Cloud早期的默认实现,由于不维护了,所以最新版本的Spring Cloud负载均衡集成的是Spring Cloud LoadBalancer(Spring Cloud官方维护)

Spring Cloud LoadBalancer快速上手

Spring Cloud LoadBalancer 并不是一个独立服务,而是一个 客户端负载均衡库

调用流程大致是:

  1. 获取服务名(例如调用 http://inventory-service/api/stock/1,这里的 inventory-service 就是服务名)。

  2. 去服务注册中心查找(Nacos、Eureka、Consul…)获取该服务的所有实例地址(IP:Port)。

  3. 负载均衡策略选择:比如轮询、随机、权重优先、本地优先。

  4. 发起请求到选定的实例

使用方式

RestTemplate 加上 @LoadBalanced 注解:

@Configuration
public class RestTemplateConfig {@Bean@LoadBalancedpublic RestTemplate restTemplate() {return new RestTemplate();}
}

使用时直接写服务名:

@Autowired
private RestTemplate restTemplate;
​
public OrderDO selectOrderById(Integer id) {OrderDO orderDO = orderMapper.selectOrderById(id);//这里的 product-service 不再是域名,而是注册中心里的 服务名。String url = "http://product-service/product/"+orderDO.getProductId();//远程调用获取数据ProductDO productDO = restTemplate.getForObject(url, ProductDO.class);orderDO.setProductDO(productDO);return orderDO;
}

启动服务进行测试

前置环境配置可参考Spring Cloud——服务注册与服务发现原理与实现-CSDN博客

测试负载均衡

连续多次发起请求: http://127.0.0.1:8080/order/1

观察product-service的日志, 会发现请求被分配到这3个实例上了

常见的负载均衡策略

Spring Cloud LoadBalancer 默认策略是 RoundRobin(轮询)。 常见策略包括:

  • RoundRobin(轮询):依次选择服务实例,分配均匀。

  • Random(随机):随机选一个实例,适合流量比较小的场景。

  • Weighted(权重):根据权重选择(Nacos 支持,可以按版本或机房区分)。

  • ZonePreference(区域优先):优先选择同机房的实例,跨机房兜底。

可以通过自定义配置扩展策略。

自定义负载均衡策略

@Configuration
public class LoadBalancerConfig {@BeanReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,LoadBalancerClientFactory loadBalancerClientFactory) {String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name,ServiceInstanceListSupplier.class), name);}
}

注意: 该类需要满足:

  1. 不用 @Configuration 注释

  2. 在组件扫描范围内

@LoadBalancerClient(name = "product-service", configuration = LoadBalancerConfig.class)
@Configuration
public class BeanConfig {@LoadBalanced@Beanpublic RestTemplate getRestTemplate(){return new RestTemplate();}
}

在 RestTemplate 配置类上方, 使用 @LoadBalancerClient 或 @LoadBalancerClients 注解, 可以对不同的服务提供方配置不同的客户端负载均衡算法策略,这样就把默认的 轮询策略替换成了 随机策略

@LoadBalancerClient 注解说明

  1. name: 该负载均衡策略对哪个服务生效(服务提供方)。

  2. configuration : 该负载均衡策略用哪个负载均衡策略实现。

LoadBalancer 原理

LoadBalancer 的实现,主要是 LoadBalancerInterceptor ,这个类会对 RestTemplate 的请求进行拦截,然后从Eureka根据服务id获取服务列表,随后利用负载均衡算法得到真实的服务地址信息,替换服务id。

我们来看看源码实现:

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

可以看到这里的intercept方法, 拦截了用户的HttpRequest请求,然后做了几件事:

  1. request.getURI() 从请求中获取uri,也就是 http://product-service/product/1001

  2. originalUri.getHost() 从uri中获取路径的主机名,也就是服务id,product-service

  3. loadBalancer.execute 根据服务id,进行负载均衡,并处理请求。

public class BlockingLoadBalancerClient implements LoadBalancerClient {
​@Overridepublic <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {String hint = this.getHint(serviceId);
​LoadBalancerRequestAdapter<T, TimedRequestContext> lbRequest =new LoadBalancerRequestAdapter<>(request, this.buildRequestContext(request, hint));
​Set<LoadBalancerLifecycle> supportedLifecycleProcessors =this.getSupportedLifecycleProcessors(serviceId);
​supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStart(lbRequest));
​// 根据 serviceId 和负载均衡策略选择处理的服务ServiceInstance serviceInstance = this.choose(serviceId, lbRequest);
​if (serviceInstance == null) {supportedLifecycleProcessors.forEach(lifecycle -> {lifecycle.onComplete(new CompletionContext(Status.DISCARD, lbRequest, new EmptyResponse()));});throw new IllegalStateException("No instances available for " + serviceId);} else {return this.execute(serviceId, serviceInstance, lbRequest);}}
​/*** 根据 serviceId 和负载均衡策略选择一个服务实例*/@Overridepublic <T> ServiceInstance choose(String serviceId, Request<T> request) {// 获取负载均衡器ReactiveLoadBalancer<ServiceInstance> loadBalancer =this.loadBalancerClientFactory.getInstance(serviceId);
​if (loadBalancer == null) {return null;} else {// 根据负载均衡算法,在列表中选择一个服务实例Response<ServiceInstance> loadBalancerResponse =(Response<ServiceInstance>) Mono.from(loadBalancer.choose(request)).block();
​return loadBalancerResponse == null ? null : loadBalancerResponse.getServer();}}
}

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

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

相关文章

鸿蒙异步处理从入门到实战:Promise、async/await、并发池、超时重试全套攻略

摘要&#xff08;介绍目前的背景和现状&#xff09; 在鸿蒙&#xff08;HarmonyOS&#xff09;里&#xff0c;网络请求、文件操作、数据库访问这类 I/O 都是异步的。主流写法跟前端类似&#xff1a;Promise、async/await、回调。想把 app 做得“流畅且不阻塞”&#xff0c;核心…

【html2img/pdf 纯!纯!python将html保存为图片/pdf!!效果非常的棒!】

素材 a.png html card.html <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><title>固定样式卡片</title><style>/* 基础样式和页面居中 */body {font-family: "微软雅黑", "P…

带宽评估(三)lossbase_v2

一、优化方向 调整丢包恢复算法的参数:可以通过调整算法中的一些参数,如丢包恢复速率、丢包恢复阈值等,来优化算法的性能。 调整发送窗口大小:在固定丢包场景下,可以通过调整发送窗口大小来控制发送速率,从而减少丢包率。 a=fmtp:96 x-google-min-bitrate=300 二、Goo…

imx6ull-驱动开发篇29——Linux阻塞IO 实验

目录 实验程序编写 blockio.c blockioApp.c Makefile 文件 运行测试 在之前的文章里&#xff0c;Linux阻塞和非阻塞 IO&#xff08;上&#xff09;&#xff0c;我们学习了Linux应用程序了两种操作方式&#xff1a;阻塞和非阻塞 IO。 在Linux 中断实验中&#xff0c;Linux…

97. 小明逛公园,Floyd 算法,127. 骑士的攻击,A * 算法

97. 小明逛公园Floyd 算法dijkstra, bellman_ford 是求单个起点到单个终点的最短路径&#xff0c;dijkstra无法解决负权边的问题&#xff0c; bellman_ford解决了负权边的问题&#xff0c;但二者都是基于单起点和单终点。而Floyd 算法旨在解决多个起点到多个终点的最短路径问题…

​崩坏世界观中的安全漏洞与哲学映射:从渗透测试视角解构虚拟秩序的脆弱性​

​崩坏世界观&#xff1a;游戏中的世界&#xff0c;是真实&#xff0c;也是虚幻的&#xff01;对于游戏中的NPC角色而言&#xff0c;TA们生存的世界&#xff0c;是真实的&#xff01;对于游戏玩家而言&#xff0c;游戏中的世界&#xff0c;是虚拟的&#xff01;通过沉浸式的游戏…

【离线安装】CentOS Linux 7 上离线部署Oracle 19c(已成功安装2次)

1.部署参考链接&#xff1a; CentOS 7 rpm方式离线安装 Oracle 19chttps://blog.csdn.net/Vampire_1122/article/details/123038137?fromshareblogdetail&sharetypeblogdetail&sharerId123038137&sharereferPC&sharesourceweixin_45806267&sharefromfrom…

小白向:Obsidian(Markdown语法学习)快速入门完全指南:从零开始构建你的第二大脑(免费好用的笔记软件的知识管理系统)、黑曜石笔记

一、认识Obsidian&#xff1a;不只是笔记软件的知识管理系统 1.1 什么是Obsidian Obsidian是一个基于本地存储的知识管理系统&#xff0c;它将你的所有笔记以纯文本Markdown格式保存在电脑本地。这个名字来源于黑曜石——一种火山熔岩快速冷却形成的玻璃质岩石&#xff0c;象…

攻防世界—Confusion1—(模板注入ssti)

一.解题在login和register的页面中发现这个文件路径接下去就找有什么点可以利用二.ssti通过题目信息可知是一只蛇把一只大象缠绕起来了&#xff0c;蛇代表python&#xff0c;大象代表php这边通过python可以推测可能是模板注入&#xff0c;这边我看其他的解题是说通过看报文信息…

【Protues仿真】基于AT89C52单片机的超声波测距

目录 1 HCSR04超声波测距传感器 1.1 基本参数 1.2 引脚说明 1.3 工作原理&#xff08;时序图&#xff09; 2 基于AT89C52单片机的超声波测距电路原理图 2.1 硬件连接说明 2.2 工作原理 3 基于AT89C52单片机的超声波测距控制程序 3.1.1 初始化设置 3.1.2 超声波测距原…

LLM - Agent核心架构:四大“身体”部件

文章目录一、Agent核心架构&#xff1a;四大“身体”部件1. 核心大脑&#xff1a;大型语言模型&#xff08;LLM&#xff09;2. 记忆系统&#xff1a;短期与长期记忆3. 工具箱&#xff08;Toolkit&#xff09;&#xff1a;从“思想家”到“行动家”4. 驱动循环&#xff08;Engin…

html-docx-js 导出word

2025.08.23今天我学习了如何将html页面内容导出到word中&#xff0c;并保持原有格式&#xff0c;效果如下&#xff1a;代码如下&#xff1a;1&#xff1a;列表页面按钮<el-button type"warning" plain icon"el-icon-download" size"mini" cli…

Science Robotics 通过人机交互强化学习进行精确而灵巧的机器人操作

机器人操作仍然是机器人技术中最困难的挑战之一&#xff0c;其方法范围从基于经典模型的控制到现代模仿学习。尽管这些方法已经取得了实质性进展&#xff0c;但它们通常需要大量的手动设计&#xff0c;在性能方面存在困难&#xff0c;并且需要大规模数据收集。这些限制阻碍了它…

Dism++备份系统时报错[句柄无效]的解决方法

当使用Dism进行系统备份时遇到“[句柄无效]”的错误&#xff0c;这通常是由于某些文件或目录的句柄无法正确访问或已被占用所导致。以下是一种有效的解决方法&#xff1a;一、查看日志文件定位日志文件&#xff1a;首先&#xff0c;打开Dism软件所在的目录&#xff0c;并找到其…

华为/思科/H3C/锐捷操作系统操作指南

好的,这是一份针对 华为(VRP)、思科(IOS/IOS-XE)、H3C(Comware)和锐捷(Ruijie OS) 这四大主流网络设备厂商操作系统的对比操作指南。本指南将聚焦于它们的共性和特性,帮助你快速掌握多厂商设备的基本操作。 四大网络厂商操作系统综合操作指南 一、 核心概念与模式对…

一文读懂 DNS:从域名解析到百度访问全流程

目录 前言 一、什么是 DNS&#xff1f;—— 互联网的 “地址簿” 为什么需要 DNS&#xff1f; DNS 的核心参数 二、DNS 解析原理&#xff1a;递归与迭代的协作 1. 两种核心查询方式 2. 完整解析流程&#xff08;以www.baidu.com为例&#xff09; 缓存清理命令 三、DNS …

初试Docker Desktop工具

文章目录1. 概述2. 下载3. 安装4. 注册5. 登录6. 启动7. 容器8. 运行容器8.1 运行容器的镜像8.2 获取示例应用8.3 验证Dockerfile文件8.4 拉取Alpine精简镜像8.5 创建镜像8.6 运行容器8.7 查看前端9. 访问静态资源9.1 本地静态资源9.2 创建服务器脚本9.3 修改Dockerfile文件9.4…

百度披露Q2财报:营收327亿,AI新业务收入首超百亿

8月20日&#xff0c;百度发布2025年第二季度财报&#xff0c;显示季度总营收327亿元&#xff0c;百度核心营收263亿元&#xff0c;归属百度核心净利润74亿元&#xff0c;同比增长35%。受AI驱动&#xff0c;涵盖智能云在内的AI新业务收入增长强劲&#xff0c;首次超过100亿元&am…

【字母异位分组】

思路 核心思路&#xff1a;使用排序后的字符串作为键&#xff0c;将原始字符串分组 键的选择&#xff1a;对于每个字符串&#xff0c;将其排序后得到标准形式作为键分组存储&#xff1a;使用哈希表&#xff0c;键是排序后的字符串&#xff0c;值是对应的原始字符串列表结果构建…

高防cdn如何缓存网页静态资源

为什么需要优化网页静态资源的缓存&#xff1f; 网页静态资源包括图片、CSS、JavaScript等文件&#xff0c;它们通常体积大、访问频繁。在网页访问过程中&#xff0c;如果每次都从源服务器请求这些静态资源&#xff0c;会导致网络延迟和带宽消耗。而优化网页静态资源的缓存&am…