LoadBalancer
LoadBalancer概述
负载均衡是什么
负载均衡(Load Balancing)是一种将用户请求合理分配到多个服务实例的技术,用于提升系统的高可用性(High Availability)与并发处理能力。通过负载均衡,可以避免单个节点过载,确保系统整体运行稳定、高效。
常见的负载均衡实现方式包括:
- 软件层面:Nginx、LVS、HAProxy 等
 - 硬件层面:F5、A10 等专业负载均衡设备
 
Spring Cloud LoadBalancer 是什么
Spring Cloud LoadBalancer是由 Spring Cloud 官方提供的一个轻量级、可扩展的客户端负载均衡组件,用于替代早期的Netflix Ribbon。- 它属于
 spring-cloud-commons模块的一部分,提供了与Ribbon类似的负载均衡能力,但实现更简洁、扩展性更强。- 除了支持 RestTemplate 外,Spring Cloud LoadBalancer 还原生支持
 WebClient(Spring WebFlux 提供的响应式异步 HTTP 客户端)。- 官网文档:https://spring.io/guides/gs/spring-cloud-loadbalancer
 
LoadBalancer 和 Nginx
- Nginx 是服务端负载均衡。客户端的所有请求首先发送到 Nginx,由 Nginx 根据配置(如轮询、权重、IP 哈希等)决定将请求转发到哪一个服务实例上。
 
- 负载均衡逻辑在服务器端执行。
 - Spring Cloud LoadBalancer 是客户端负载均衡。
 
- 当服务消费者调用远程服务时,会先从注册中心获取可用服务实例列表并缓存到本地(JVM 内存中)。
 - 每次调用时,根据负载均衡算法(如轮询、随机等)在本地选择一个实例进行调用。
 - 负载均衡逻辑在客户端完成。
 
关于Ribbon
- Spring Cloud Ribbon 是基于
 Netflix Ribbon实现的客户端负载均衡工具。- Ribbon 是 Netflix 开源的客户端负载均衡库,提供多种负载均衡算法和可配置选项(如连接超时、重试策略等)。
 - 随着 Spring Cloud 官方组件的演进,
 Ribbon已进入维护模式,官方推荐使用Spring Cloud LoadBalancer作为替代方案。
负载均衡演示
架构说明
订单服务(cloud-consumer-order80) 通过轮询负载均衡的方式访问多个支付服务实例(cloud-provider-payment8001、8002、8003),实现请求分发与高可用。
Spring Cloud LoadBalancer 的工作流程分为两个阶段:
第一步:
服务发现LoadBalancer 首先从服务注册中心(如 Consul、Eureka、Nacos 等)拉取可用服务实例列表。例如,支付服务共有三个实例:8001、8002、8003,这些实例提供相同的功能,客户端可以任选其一进行调用。类比现实场景,就像挂号系统中某个科室的多位医生,患者可以选择其中任意一位就诊。
第二步:
负载均衡选择客户端根据负载均衡算法(如轮询、随机等)从本地缓存的服务列表中选择一个实例地址并发起请求。因此,LoadBalancer 是一种客户端负载均衡机制,负载均衡的决策逻辑发生在客户端,而不是服务端。
演示步骤
参考官方文档:https://docs.spring.io/spring-cloud-commons/reference/spring-cloud-commons/loadbalancer.html
创建多个支付模块
- 复制8001的配置,并覆盖端口号属性,然后运行多个支付模块。这里为了让Services面板看起来整洁,对多个服务进行了分组(选择某个服务,右键选择group configurations)
 
- 启动Consul,然后启动8001、8002、8003、80四个模块
 
- 查看Consul控制台:
 http://localhost:8500/
支付模块8001新增controller
package com.sun.cloud.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class ConsulController { @Value("${server.port}") private String port; @GetMapping(value = "/consul/info") private String getInfoByConsul() { return "支付模块提供服务,端口号为:" + port; } }
订单模块80增加RestTemplate配置类
之前已经创建过这个类了,就不用再创建了。这里只是说明一下,该类是进行远程方法调用必须创建的。当然,后面可以用OpenFeign来替代RestTemplate。
package com.sun.cloud.config; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; @Configuration public class RestTemplateConfig { @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } }
订单模块80新增controller
在controller中,通过
RestTemplate来调用8001中的方法。package com.sun.cloud.controller; import jakarta.annotation.Resource; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @RestController public class ConsulController { @Resource RestTemplate restTemplate; // 远程服务地址 private static final String PaymentSrv_URL = "http://cloud-payment-service"; @GetMapping(value = "/consul/info") public String getPaymentInfo() { return restTemplate.getForObject(PaymentSrv_URL + "/consul/info", String.class); } }
测试
重启8001、8002、8003、80四个模块,进行测试
根据上图可知道。不需要添加任何配置,默认已经实现了负载均衡。因为
spring-cloud-starter-consul-discovery中已经引用了spring-cloud-starter-loadbalancer依赖。所以可以不用在80订单模块的pom.xml文件中再显式引入该依赖。如果其他依赖没有引入
loadbalancer的依赖,则必须在pom.xml进行添加。<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency>
负载均衡算法原理
默认实现的算法有两种:
RoundRobinLoadBalancer
RoundRobinLoadBalancer是 Spring Cloud LoadBalancer 的默认策略。它会按照请求顺序,依次循环选择服务实例。核心原理:
- 每次请求时,内部维护一个自增计数器(AtomicInteger)。
 - 通过
 currentIndex = (counter++) % instanceCount计算出目标实例的下标。- 实现简单,能保证请求均匀分布在所有可用实例上。
 优点:
- 简单高效,适合大多数场景。
 - 不依赖实例性能或响应时间。
 缺点:
- 未考虑实例健康状态和性能差异。
 RandomLoadBalancer
RandomLoadBalancer使用 随机算法 在服务实例中选择目标节点。每次请求时,从可用实例列表中随机选取一个进行调用。核心原理:
- 获取当前可用实例集合。
 - 使用
 ThreadLocalRandom.current().nextInt(instanceCount)生成随机下标。- 返回对应实例完成调用。
 优点:
- 简单、均衡,适用于实例数量变化频繁的场景。
 缺点:
- 可能造成短时间内请求集中到同一实例,随机分布不稳定。
 
获取所有上线的服务列表
通过下面的方法,就能获取到注册进Consul中的所有服务的信息。获取到该信息后,保存在本地,再结合负载均衡算法来选择一个服务实例,就能实现服务的负载均衡了。
package com.sun.cloud.controller; import jakarta.annotation.Resource; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController public class DiscoveryClientController { @Resource private DiscoveryClient discoveryClient; // 记录当前是第几次请求 private Integer requestCount = 0; @GetMapping("/discovery") public String discovery() { // 获取服务列表 List<String> services = discoveryClient.getServices(); services.forEach(System.out::println); System.out.println("==================================="); // 获取某个服务的实例列表 List<ServiceInstance> instances = discoveryClient.getInstances("cloud-payment-service"); instances.forEach(instance -> { System.out.println(instance.getServiceId() + "\t" + instance.getHost() + "\t" + instance.getPort() + "\t" + instance.getUri()); }); // 负载均衡获取服务实例 int index = requestCount % instances.size(); requestCount++; return instances.get(index).getServiceId() + " : " + instances.get(index).getUri(); } }对上面的controller进行测试。
- 获取到所有的服务实例
 
- 通过负载均衡,返回服务实例
 
负载均衡算法切换
定义负载均衡策略
package com.sun.cloud.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; // 定义使用的负载均衡器 // 注意:不能使用 @Configuration 标注此类为配置类,否则会抛出异常 public class LoadBalancerConfig { @Bean ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) { String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME); return new RandomLoadBalancer(loadBalancerClientFactory .getLazyProvider(name, ServiceInstanceListSupplier.class), name); } }
配置负载均衡策略
由于远程调用使用的是
RestTemplate,所以要在RestTemplate的配置类中加上@LoadBalancerClient注解,并且指明是对哪个服务生效以及采用的负载均衡策略。
- value:指定服务的名称(即注册到服务注册中心的服务名)。通过该属性,可以为某个具体的服务配置自定义的负载均衡逻辑。
 - configuration:指定一个或多个配置类,这些类可以用来为指定的服务提供自定义的负载均衡逻辑或规则。
 package com.sun.cloud.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; @Configuration @LoadBalancerClient(value = "cloud-payment-service", configuration = LoadBalancerConfig.class) public class RestTemplateConfig { @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } }配置好后,重启80服务。访问:
http://localhost/consul/info,每次调用服务的实例就是随机的。










