Skip to content

LoadBalancer 详解:Spring 官方客户端负载均衡

Spring Cloud LoadBalancer 是 Spring 官方推出的客户端负载均衡器,替代了已停维的 Netflix Ribbon。基于响应式(Reactive)架构,非阻塞,性能更好,是当前 Spring Cloud 2020+ 版本的默认负载均衡方案。

一、为什么需要 LoadBalancer?

Ribbon 在 2020 年进入维护模式后,Spring 官方需要一个新的负载均衡方案。LoadBalancer 的定位是:

  1. 响应式架构:基于 Project Reactor,非阻塞 IO,线程资源利用率更高
  2. 官方维护:Spring 团队持续迭代,与 Spring Cloud 版本同步演进
  3. 轻量化:去掉 Ribbon 中不常用的功能,保持核心能力简洁
  4. 可扩展:支持自定义策略,与 Nacos 等服务发现组件深度集成

二、核心架构

LoadBalancer 的设计围绕两个核心抽象:

                    ┌──────────────────────────┐
                    │   ReactiveLoadBalancer    │
                    │      选择实例的接口         │
                    └──────────┬───────────────┘


                    ┌──────────────────────────┐
                    │ ServiceInstanceListSupplier│
                    │     提供实例列表的接口       │
                    └──────────┬───────────────┘


                    ┌──────────────────────────┐
                    │    DiscoveryClient        │
                    │   从注册中心获取实例         │
                    └──────────────────────────┘
组件接口职责
ReactiveLoadBalancerReactiveLoadBalancer<T>负载均衡核心接口,从实例列表中选一个
ServiceInstanceListSupplierServiceInstanceListSupplier提供实例列表(从注册中心获取)
LoadBalancerClientFactoryLoadBalancerClientFactory为每个服务创建独立的 LoadBalancer 实例

调用流程:

1. Feign 拦截请求 → 提取服务名 "order-service"
2. LoadBalancerClientFactory 获取 order-service 对应的 LoadBalancer
3. ServiceInstanceListSupplier 从 Nacos/Consul 获取实例列表
4. ReactiveLoadBalancer 按策略选一个实例
5. 返回选中的实例,Feign 构造 HTTP 请求发送

三、内置负载均衡策略

3.1 RoundRobinLoadBalancer(默认)

轮询策略,依次选择实例,简单公平。默认实现,无需额外配置。

3.2 RandomLoadBalancer

随机选择实例。需要手动配置:

java
@Configuration
@LoadBalancerClient(name = "order-service", configuration = RandomLoadBalancerConfig.class)
public class RandomLoadBalancerConfig {
    @Bean
    public ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(
            Environment env, LoadBalancerClientFactory factory) {
        String name = env.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new RandomLoadBalancer(
            factory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
    }
}

3.3 NacosLoadBalancer(Nacos 权重)

当使用 Nacos 作为注册中心时,自动启用 Nacos 的权重策略。实例的权重在 Nacos 控制台配置,权重越高分配到的请求越多。

yaml
spring:
  cloud:
    loadbalancer:
      nacos:
        enabled: true

权重规则: 假设 3 个实例权重分别为 5、3、2,则请求分配比例为 5:3:2。

四、自定义负载均衡策略

实现 ReactorLoadBalancer 接口即可自定义策略。以下是一个"最小连接数"策略的示例:

java
@Configuration
public class CustomLoadBalancerConfig {

    @Bean
    public ReactorLoadBalancer<ServiceInstance> minConnectionsLoadBalancer(
            Environment env, LoadBalancerClientFactory factory) {
        String name = env.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new ReactorLoadBalancer<ServiceInstance>() {
            private final Map<String, AtomicInteger> connections = new ConcurrentHashMap<>();

            @Override
            public Mono<Response<ServiceInstance>> choose(Request request) {
                ServiceInstanceListSupplier supplier = factory
                    .getLazyProvider(name, ServiceInstanceListSupplier.class)
                    .getIfAvailable();
                if (supplier == null) {
                    return Mono.empty();
                }
                return supplier.get().next().flatMap(instances -> {
                    if (instances.isEmpty()) {
                        return Mono.empty();
                    }
                    // 选择连接数最少的实例
                    ServiceInstance selected = instances.stream()
                        .min(Comparator.comparingInt(i ->
                            connections.getOrDefault(i.getHost() + ":" + i.getPort(),
                                new AtomicInteger(0)).get()))
                        .orElse(instances.get(0));
                    connections.computeIfAbsent(
                        selected.getHost() + ":" + selected.getPort(),
                        k -> new AtomicInteger(0)).incrementAndGet();
                    return Mono.just(new DefaultResponse(selected));
                });
            }

            @Override
            public Mono<Response<ServiceInstance>> choose(Request request, ServiceInstanceList suppliers) {
                return choose(request);
            }
        };
    }
}

在 Feign 接口上指定配置:

java
@FeignClient(
    name = "order-service",
    configuration = CustomLoadBalancerConfig.class
)
public interface OrderClient {
    // ...
}

五、核心配置

yaml
spring:
  cloud:
    loadbalancer:
      retry:
        enabled: true                # 开启重试,失败后换实例
        retry-on-all-operations: false  # 只对 GET 请求重试
      cache:
        enabled: true                # 开启实例列表缓存
        ttl: 35s                     # 缓存过期时间
        capacity: 256                # 缓存容量
      health-check:
        initial-delay: 0             # 首次健康检查延迟
        interval: 25s                # 健康检查间隔
        refetch-instances-interval: 25s  # 重新拉取实例列表间隔
      nacos:
        enabled: true                # 启用 Nacos 权重策略

六、与 Feign 的协作

Spring Cloud 2020+ 版本中,Feign 默认不再依赖 Ribbon,而是使用 LoadBalancer:

@FeignClient(name = "order-service")


Feign 拦截调用 → 提取服务名 → 交给 LoadBalancer


LoadBalancer 从 Nacos/Consul 获取实例列表


ReactiveLoadBalancer 选择实例


Feign 构造 HTTP 请求 → 发送到选中的实例

关键差异: Feign 本身是阻塞式的,LoadBalancer 是响应式的。Spring Cloud 内部做了适配,通过 BlockingLoadBalancerClient 将响应式调用转为阻塞,对 Feign 透明。

七、从 Ribbon 迁移到 LoadBalancer

迁移项Ribbon(旧)LoadBalancer(新)
依赖spring-cloud-starter-netflix-ribbon已内置,无需额外依赖
策略配置order-service.ribbon.NFLoadBalancerRuleClassName@LoadBalancerClient 注解
自定义策略implements IRuleimplements ReactorLoadBalancer
重试配置ribbon.MaxAutoRetriesspring.cloud.loadbalancer.retry.enabled
超时配置ribbon.ConnectTimeoutHTTP 客户端层面配置(如 feign.client.config
权重策略需自定义Nacos 原生支持

迁移步骤:

  1. 移除 Ribbon 依赖(Spring Cloud 2020+ 已默认移除)
  2. ribbon.xxx 配置改为 spring.cloud.loadbalancer.xxx
  3. 将自定义的 IRule 实现改为 ReactorLoadBalancer 实现
  4. 启用 spring.cloud.loadbalancer.nacos.enabled=true(如使用 Nacos)

八、面试要点

Q:为什么用 LoadBalancer 替代 Ribbon?

Ribbon 已停维,基于阻塞式 IO;LoadBalancer 是 Spring 官方维护,基于响应式架构,非阻塞,性能更好,且与 Spring Cloud 版本同步演进。

Q:LoadBalancer 和 Ribbon 的区别?

维度RibbonLoadBalancer
维护方Netflix(已停维)Spring 官方(活跃)
编程模型阻塞式响应式(Reactive)
内置策略7 种2 种(轮询 + 随机)
权重策略需自定义Nacos 原生支持
依赖独立引入已内置

Q:Feign + LoadBalancer 如何实现负载均衡?

Feign 拦截 @FeignClient 调用,提取服务名交给 LoadBalancer。LoadBalancer 从注册中心获取实例列表,按策略选一个实例返回给 Feign。Feign 构造 HTTP 请求发送到选中的实例。整个过程通过 BlockingLoadBalancerClient 桥接响应式与阻塞式调用。

Q:如何自定义 LoadBalancer 的负载均衡策略?

实现 ReactorLoadBalancer<ServiceInstance> 接口,在 @LoadBalancerClient@LoadBalancerClients 注解中指定配置类,配置类中注册自定义的 ReactorLoadBalancer Bean。