Spring Cloud:分布式系统的“粘合剂”(四)
专栏Spring Cloud个人主页手握风云目录一、负载均衡1.1. 问题1.2. 定义1.3. 分类二、Spring Cloud LoadBalancer2.1. 快速上手2.2. 负载均衡策略2.3. 底层原理三、多机部署3.1. 前置准备3.2. Maven 项目打包3.3. 服务器 Jar 包上传与后台启动一、负载均衡1.1. 问题在前面的远程调用基础代码中程序会通过 DiscoveryClient 根据服务名称拉取完整的服务实例列表但代码逻辑固定选取列表下标为 0 的第一个实例发起请求。这种写法在服务仅部署单实例时不会出现问题可一旦同一服务启动多份实例流量会全部集中到首个实例多节点扩容的价值完全无法发挥。右键服务启动配置选择 Copy Configuration 复制配置再通过 Modify options 菜单栏添加 VM 启动参数 -Dserver.port端口号以此修改不同实例的占用端口。本次演示共启动 3 个 product-service 服务端口分别为 9090、9091、9092全部注册至 Eureka 注册中心。package com.yang.order.service; import com.yang.order.mapper.OrderMapper; import com.yang.order.model.OrderInfo; import com.yang.order.model.ProductInfo; import jakarta.annotation.PostConstruct; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; Slf4j Service public class OrderService { Autowired private OrderMapper orderMapper; Autowired private RestTemplate restTemplate; Autowired private DiscoveryClient discoveryClient; private AtomicInteger count new AtomicInteger(1); private ListServiceInstance instances; PostConstruct public void init() { //从Eureka中获取服务列表 instances discoveryClient.getInstances(product-service); } public OrderInfo selectOrderById(Integer orderId) { OrderInfo orderInfo orderMapper.selectOrderById(orderId); // 通过计数器 % 实例 下标索引 int index count.getAndIncrement() % instances.size(); String uri instances.get(index).getUri().toString(); String url uri /product/ orderInfo.getProductId(); log.info(远程调用url:{}, url); ProductInfo productInfo restTemplate.getForObject(url, ProductInfo.class); orderInfo.setProductInfo(productInfo); return orderInfo; } }借助 AtomicInteger 实现原子自增计数通过计数值对实例列表长度取模循环选中不同服务实例改造代码后重新测试请求会均匀分配至三台实例直观展现出负载均衡的基础效果。1.2. 定义负载均衡英文缩写为 LB是构建高并发、高可用分布式系统不可或缺的核心组件。随着业务流量持续上涨开发者通常会通过新增服务节点完成水平扩容而负载均衡的核心作用就是按照预设规则将客户端流量合理分摊到多台服务机器避免单节点压力过载整体提升集群的处理效率。团队初期仅一名员工工作量提升后新增多名员工负载均衡就相当于分配工作的规则均衡分摊任务充分发挥团队整体处理能力和多服务实例分流流量的设计思路完全一致。1.3. 分类真实业务场景下负载均衡的分配规则十分丰富除基础轮询外还可根据服务器硬件性能分配流量硬件配置更高的节点承载更多请求。为统一标准化实现行业内衍生出两类成熟的负载均衡架构分别是服务端负载均衡与客户端负载均衡二者最核心的区分标准是服务实例清单的存储位置。第一类是服务端负载均衡典型代表工具为 Nginx。整体流程为用户请求先统一发送到独立的负载均衡中间设备由均衡器存储全部后端服务清单通过内置算法挑选节点后转发请求所有流量都需要经过这一台集中式设备中转。第二类是客户端负载均衡功能以 SDK 类库的形式集成在调用方服务内部无需独立中间设备。Spring Cloud 早期采用 Ribbon 组件实现该能力但该组件已停止维护2020.0.1 及以上新版本统一使用官方自研的 Spring Cloud LoadBalancer。执行流程为客户端先向 Eureka 注册中心拉取全部可用服务实例列表在本地运行负载均衡算法筛选目标节点之后直接与选中的服务实例建立连接发起调用。二、Spring Cloud LoadBalancer2.1. 快速上手Spring Cloud 在 2020.0.1 版本之后正式移除了原有的 Ribbon 组件改用 Spring Cloud LoadBalancer 作为官方默认的客户端负载均衡实现方案也是当前新项目统一采用的标准组件。想要快速启用该组件实现负载均衡仅需完成两步核心配置。第一步是改造 RestTemplate 的 Bean 配置在创建 RestTemplate 的方法上添加 LoadBalanced 注解该注解会开启负载均衡拦截能力为后续服务名转发提供基础支撑。第二步需要修改远程调用的请求地址摒弃硬编码的 IP 与端口直接使用注册中心内注册的服务名称拼接 URL例如把 http://127.0.0.1:9090/product/{id} 替换为 http://product-service/product/{id}。package com.yang.order.config; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer; import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer; import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier; import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory; import org.springframework.context.annotation.Bean; import org.springframework.core.env.Environment; public class CustomLoadBalancerConfiguration { Bean ReactorLoadBalancerServiceInstance randomLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) { String name environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME); return new RandomLoadBalancer(loadBalancerClientFactory .getLazyProvider(name, ServiceInstanceListSupplier.class), name); } }package com.yang.order.config; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; LoadBalancerClient(name product-service, configuration CustomLoadBalancerConfiguration.class) Configuration public class BeanConfig { Bean LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } }Spring Cloud LoadBalancerpackage com.yang.order.service; import com.yang.order.mapper.OrderMapper; import com.yang.order.model.OrderInfo; import com.yang.order.model.ProductInfo; import jakarta.annotation.PostConstruct; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; /** * author gao * date 2026/7/22 11:34 */ Slf4j Service public class OrderService { Autowired private OrderMapper orderMapper; Autowired private RestTemplate restTemplate; Autowired private DiscoveryClient discoveryClient; private AtomicInteger count new AtomicInteger(1); private ListServiceInstance instances; PostConstruct public void init() { //从Eureka中获取服务列表 instances discoveryClient.getInstances(product-service); } public OrderInfo selectOrderById(Integer orderId) { OrderInfo orderInfo orderMapper.selectOrderById(orderId); String url http://product-service/product/ orderInfo.getProductId(); log.info(远程调用url:{}, url); ProductInfo productInfo restTemplate.getForObject(url, ProductInfo.class); orderInfo.setProductInfo(productInfo); return orderInfo; } }持续重复调用订单接口 http://127.0.0.1:8080/order/1 进行功能验证查看三个 product-service 实例的运行日志能够清晰发现请求会自动分发到三台不同实例负载均衡能力正式生效。2.2. 负载均衡策略负载均衡策略是一套通用的流量分配逻辑不管是服务端均衡器还是客户端均衡组件底层设计思路都高度相似。Spring Cloud LoadBalancer 内置仅提供两种原生负载均衡策略分别是轮询策略与随机策略。轮询策略 RoundRobin 是组件默认使用的分配方案逻辑为请求按照顺序轮流分配给集群内每一台可用实例实现简单、适用绝大多数常规业务场景。随机选择 Random 策略则是每次发起请求时从全部可用实例中随机挑选一台处理请求分配逻辑无固定顺序。如果业务场景需要切换为随机策略支持自定义负载均衡算法实现。首先需要新建负载均衡配置类 LoadBalancerConfig在类中注入 RandomLoadBalancer 类型的 Bean同时有两个硬性要求配置类不能标注 Configuration 注解且该类需要处于 Spring 组件扫描范围内。完成策略 Bean 编写后还需要借助 LoadBalancerClient 注解绑定策略与目标服务。该注解添加在 RestTemplate 配置类上方其中 name 属性指定需要生效负载均衡策略的服务名称configuration 属性指向自定义的策略配置类。项目中仅存在 product-service 一个服务提供者因此直接使用单服务绑定注解LoadBalancerClient即可完成配置。2.3. 底层原理Spring Cloud LoadBalancer 的核心拦截载体是 LoadBalancerInterceptor该拦截器会拦截所有通过 RestTemplate 发起的 HTTP 远程调用自动完成服务名解析、实例筛选、地址替换全流程操作。public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor { private LoadBalancerClient loadBalancer; private LoadBalancerRequestFactory requestFactory; public LoadBalancerInterceptor(LoadBalancerClient loadBalancer, LoadBalancerRequestFactory requestFactory) { this.loadBalancer loadBalancer; this.requestFactory requestFactory; } public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) { this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer)); } public 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 拦截方法后第一步会读取请求原始 URI提取 URI 中的 Host 作为服务 ID也就是我们拼接 URL 时填写的服务名称 product-service第二步调用 LoadBalancerClient 的 execute 执行方法传入解析得到的服务 ID进入实例选择逻辑。在 BlockingLoadBalancerClient 的 execute 方法内部会先调用 choose 方法执行负载均衡筛选。程序会根据服务 ID 获取对应的负载均衡器再调用均衡器内置的 choose 方法基于预设的轮询或随机策略从 Eureka 拉取的服务实例列表中选出一台可用 ServiceInstance。如果筛选后没有找到任何可用实例程序会直接抛出无服务实例异常若成功获取有效实例则将请求 URL 中的服务名替换为实例真实 IP 与端口最终发起远程调用完成一整套客户端负载均衡流程。三、多机部署3.1. 前置准备服务器安装 MySQL导入业务初始化 SQL修改项目配置文件替换数据库连接账号、密码适配服务器 MySQL。3.2. Maven 项目打包分别对 3 个微服务打包eureka-server、order-service、product-service标准 SpringBoot Maven 打包流程。3.3. 服务器 Jar 包上传与后台启动Eureka、Order 单实例启动Product 多实例通过 --server.port端口 区分端口分别输出独立日志文件

相关新闻

Unity责任链模式实战:游戏事件处理与代码解耦

Unity责任链模式实战:游戏事件处理与代码解耦

1. 项目概述:为什么Unity开发者需要掌握责任链模式?如果你在Unity里写过稍微复杂一点的逻辑,比如处理一个UI按钮点击后要经过登录验证、资源检查、冷却判断、最终执行一连串操作,或者处理一个游戏事件需要被多个系统(音…

2026/10/20 13:41:33 阅读更多 →
Claude Opus在ARC-AGI-3基准测试创SOTA:AGI评估标准变革与开发实践

Claude Opus在ARC-AGI-3基准测试创SOTA:AGI评估标准变革与开发实践

最近在 AI 圈子里,一个消息引起了不小的震动:Claude Opus 在 ARC-AGI-3 基准测试中创下了新的 SOTA(State-of-the-Art)成绩。但如果你以为这只是又一个“模型刷榜”的新闻,那就错过了真正重要的信息。这个成绩背后真正…

2026/10/17 16:12:48 阅读更多 →
NopCommerce插件开发实战指南:从入门到部署

NopCommerce插件开发实战指南:从入门到部署

1. NopCommerce插件开发概述NopCommerce作为目前最流行的开源电商系统之一,其插件机制为开发者提供了强大的扩展能力。在4.9.3版本中,插件架构经过多次优化,开发体验更加友好。我最近刚完成一个支付网关插件的开发,过程中积累了不…

2026/10/19 23:23:29 阅读更多 →

最新新闻

从日榜看技术趋势:Rust崛起与AI应用层霸榜的深度拆解

从日榜看技术趋势:Rust崛起与AI应用层霸榜的深度拆解

1. 日榜项目的整体观察与拆解思路每天早上刷一遍热榜,已经成了我这些年做技术选型和趋势判断的固定动作。2026年10月8日这一期的日榜,整体看下来有一个很明显的特征:工具类项目占比超过六成,AI 应用层项目继续霸榜,但底…

2026/10/20 13:40:50 阅读更多 →
日榜速报:从开源趋势到技术选型的评估方法论

日榜速报:从开源趋势到技术选型的评估方法论

1. 日榜速报到底在解决什么信息焦虑每天早上打开代码托管平台,首页那个趋势榜单就像一份技术圈的晨报。但问题在于,榜单只给你一个仓库名和一句话简介,至于它为什么突然冲上来、背后用了什么技术栈、值不值得你花半小时去克隆下来跑一遍&…

2026/10/20 13:40:50 阅读更多 →
C++中变量进行初始化的3种方法

C++中变量进行初始化的3种方法

前言 「变量初始化有哪几种写法」这个问题,答案取决于你按什么维度分类。按语法形式分,最常说的是三种:复制初始化(copy-initialization,int a 1;)、直接初始化(direct-initialization&#xf…

2026/10/20 13:40:50 阅读更多 →
Serverpod客户端鸿蒙适配:端云屏障与序列化同步实战指南

Serverpod客户端鸿蒙适配:端云屏障与序列化同步实战指南

1. 为什么专门聊“Serverpod客户端的鸿蒙适配”1.1 Serverpod到底解决了什么问题这几年用 Flutter 做跨端业务,最舒服的一点就是 UI 层可以一套代码铺到手机、平板、桌面,甚至嵌入式设备。但等到真要对接后端的时候,很多人会突然发现一个问题…

2026/10/20 13:40:50 阅读更多 →
机器视觉框架实战:AOI检测与机械手定位引导全解析

机器视觉框架实战:AOI检测与机械手定位引导全解析

搞机器视觉的兄弟应该都有过这种经历:项目接下来,相机、镜头、光源选型好解决,真正的坑全在工程层。视觉检测模板要调,AOI缺陷检测要同时顶住误检和漏检两头压力,机械手定位要做手眼标定,一套流程捋下来&am…

2026/10/20 13:40:50 阅读更多 →
Kafka消息顺序性真相:从分区内有序到生产消费端全链路保序实践

Kafka消息顺序性真相:从分区内有序到生产消费端全链路保序实践

搞过分布式消息的同学应该都遇到过这类问题:明明往Kafka里发消息的时候还想着要顺序,等消费端一跑起来,订单状态直接被回滚回退,或者用户余额扣减顺序反了,一时半会又查不出问题在哪。我之前接手过一个订单系统&#x…

2026/10/20 13:39:46 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →