SpringCloud LoadBalancer负载均衡
在微服务架构中,客户端负载均衡是保障服务高可用与高性能的关键组件。Spring Cloud LoadBalancer 作为 Spring Cloud 官方推出的新一代负载均衡器,不仅提供了轻量级的内置策略,还支持灵活的自定义扩展,完美适配现代响应式编程模型。本文将深入解析其核心原理、与 Ribbon 的主要区别,并通过从基础使用到自定义策略的完整示例,帮助您快速掌握这一重要工具,为构建健壮的微服务系统打下坚实基础。
一,Spring Cloud LoadBalancer原理
Spring Cloud LoadBalancer是Spring Cloud官方推出的客户端负载均衡组件,核心工作原理如下:
1. 核心执行流程
客户端从Nacos/Eureka等注册中心拉取可用服务实例列表,缓存到本地。
通过LoadBalancerClientFactory获取对应服务的负载均衡器实例。
调用内置的choose()方法,基于轮询/随机等预设策略,从实例列表中选中一个目标服务节点。
重构请求URL,直接向选中的实例发起远程调用。
2. 核心内置实现
它提供了两个默认负载均衡器:
RoundRobinLoadBalancer:轮询策略,按顺序依次分发请求,是默认策略。
RandomLoadBalancer:随机策略,随机从可用实例中挑选节点。
同时支持通过实现ReactorServiceInstanceLoadBalancer接口,快速自定义负载均衡策略。
3. 关键特性
它同时支持阻塞式和响应式编程模型,适配RestTemplate、Feign、WebClient等多种调用方式,完全替代已停更的Ribbon组件,适配新版Spring Cloud全生态。
二,Spring Cloud LoadBalancer和Ribbon的核心区别如下:
一、基础定位与维护状态
Ribbon:Netflix开源的老牌负载均衡组件,目前已停止官方维护,仅适配Spring Cloud早期版本。
Spring Cloud LoadBalancer:Spring Cloud官方自研的新一代负载均衡组件,是官方指定的Ribbon替代方案,持续迭代更新,适配所有新版本Spring Cloud。
二、核心特性差异
编程模型:Ribbon仅支持传统阻塞式编程;LoadBalancer同时支持阻塞式和响应式编程,适配WebFlux等现代技术栈。
内置策略:Ribbon提供7种以上内置负载均衡策略;LoadBalancer默认仅内置轮询、随机两种基础策略,更轻量化,支持快速自定义扩展。
生态兼容性:Ribbon和Eureka、Hystrix等旧版Netflix生态深度绑定;LoadBalancer原生适配Nacos、Spring Cloud Gateway等新一代Spring Cloud生态组件。
三、适用场景
Ribbon:仅适合维护老旧Spring Cloud项目,不建议新项目使用。
Spring Cloud LoadBalancer:所有新开发的微服务项目的首选方案,性能更优、扩展性更强,长期维护性更好。
三、简单示例
下面是一个使用 Spring Cloud LoadBalancer 配合 WebClient 进行服务调用的简单示例。
1. 添加依赖
在 pom.xml 中添加必要的依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
2. 配置启用负载均衡
确保您的应用已连接到服务注册中心(如 Nacos、Eureka)。
3. 创建负载均衡的 WebClient
使用 @LoadBalanced 注解创建一个具备负载均衡能力的 WebClient.Builder Bean。
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;
@Configuration
public class WebClientConfig {
@Bean
@LoadBalanced
public WebClient.Builder loadBalancedWebClientBuilder() {
return WebClient.builder();
}
}
4. 使用 WebClient 调用服务
在您的服务类中注入 WebClient.Builder,并使用服务名(而非具体IP和端口)发起请求。
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
@Service
public class UserService {
private final WebClient webClient;
public UserService(WebClient.Builder webClientBuilder) {
// 使用服务名 "user-service" 构建 WebClient
this.webClient = webClientBuilder.baseUrl("http://user-service").build();
}
public Mono<String> getUserInfo(Long userId) {
return this.webClient
.get()
.uri("/users/{id}", userId)
.retrieve()
.bodyToMono(String.class);
}
}
示例说明:
- 当调用
getUserInfo方法时,WebClient会通过 Spring Cloud LoadBalancer 将请求http://user-service/users/{id}负载均衡到名为user-service的某个健康实例上。 - LoadBalancer 会自动从注册中心获取
user-service的实例列表,并依据默认的轮询策略选择一个实例。
通过以上几步,您就完成了一个简单的、具备客户端负载均衡能力的服务调用。
4. 自定义负载均衡策略示例
Spring Cloud LoadBalancer 支持通过实现 ReactorServiceInstanceLoadBalancer 接口来自定义负载均衡策略。下面展示一个简单的基于权重的选择策略示例,假设每个服务实例有一个权重属性,权重越高的实例被选中的概率越大。
4.1 实现自定义负载均衡器
创建一个实现 ReactorServiceInstanceLoadBalancer 接口的类:
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.DefaultResponse;
import org.springframework.cloud.client.loadbalancer.EmptyResponse;
import org.springframework.cloud.client.loadbalancer.Request;
import org.springframework.cloud.client.loadbalancer.Response;
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import reactor.core.publisher.Mono;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
public class WeightedLoadBalancer implements ReactorServiceInstanceLoadBalancer {
private final String serviceId;
private final List<ServiceInstance> serviceInstances;
public WeightedLoadBalancer(String serviceId, List<ServiceInstance> serviceInstances) {
this.serviceId = serviceId;
this.serviceInstances = serviceInstances;
}
@Override
public Mono<Response<ServiceInstance>> choose(Request request) {
if (serviceInstances.isEmpty()) {
return Mono.just(new EmptyResponse());
}
// 计算总权重
int totalWeight = serviceInstances.stream()
.mapToInt(instance -> getWeight(instance))
.sum();
if (totalWeight <= 0) {
// 如果所有实例权重都<=0,则随机选择一个
int randomIndex = ThreadLocalRandom.current().nextInt(serviceInstances.size());
return Mono.just(new DefaultResponse(serviceInstances.get(randomIndex)));
}
// 生成一个 [0, totalWeight) 的随机数
int randomWeight = ThreadLocalRandom.current().nextInt(totalWeight);
int currentWeight = 0;
// 按权重区间选择实例
for (ServiceInstance instance : serviceInstances) {
currentWeight += getWeight(instance);
if (randomWeight < currentWeight) {
return Mono.just(new DefaultResponse(instance));
}
}
// 兜底:返回第一个实例
return Mono.just(new DefaultResponse(serviceInstances.get(0)));
}
/**
* 从实例的元数据(metadata)中获取权重值,默认权重为1
*/
private int getWeight(ServiceInstance instance) {
String weightStr = instance.getMetadata().get("weight");
if (weightStr != null) {
try {
return Integer.parseInt(weightStr);
} catch (NumberFormatException e) {
// 解析失败则返回默认权重
}
}
return 1; // 默认权重
}
}
4.2 配置自定义负载均衡器
创建一个配置类,将自定义的负载均衡器注册到 Spring 容器中:
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import java.util.List;
@Configuration
public class LoadBalancerConfiguration {
@Bean
@Primary
public ReactorServiceInstanceLoadBalancer customLoadBalancer(
DiscoveryClient discoveryClient,
ServiceInstanceListSupplier supplier) {
return serviceInstanceList -> supplier.get()
.next()
.map(instances -> {
// 这里可以针对特定服务进行配置
String serviceId = "user-service"; // 替换为你的服务名
List<ServiceInstance> serviceInstances = discoveryClient.getInstances(serviceId);
return new WeightedLoadBalancer(serviceId, serviceInstances);
});
}
}
4.3 为服务实例配置权重
在服务实例的注册信息中添加权重元数据。以 Nacos 为例,在服务的 bootstrap.yml 或 application.yml 中配置:
spring:
cloud:
nacos:
discovery:
metadata:
weight: "3" # 权重值,数字越大被选中的概率越高
4.4 使用自定义策略
应用启动后,所有对 user-service 的负载均衡请求都会使用我们实现的权重策略。你无需修改之前的 WebClient 调用代码,LoadBalancer 会自动使用注册的自定义负载均衡器。
实现原理说明:
WeightedLoadBalancer从服务实例的元数据中读取weight字段作为权重值。- 选择时根据所有权重值总和生成随机数,落在哪个实例的权重区间就选择哪个实例。
- 权重越高,区间范围越大,被选中的概率就越高。
- 通过
LoadBalancerConfiguration将自定义负载均衡器注册为特定服务的默认实现。
通过这个示例,你可以看到 Spring Cloud LoadBalancer 的自定义扩展非常灵活,只需实现一个接口即可定义复杂的负载均衡逻辑。
更多推荐



所有评论(0)