乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • 学习路径
  • 第1章 微服务与 Spring Cloud 概述

    • 微服务与 Spring Cloud 概述
  • 第2章 服务注册与发现

    • Eureka 服务注册与发现
    • Consul 服务注册与发现
  • 第3章 客户端负载均衡

    • Ribbon 客户端负载均衡
    • Spring Cloud LoadBalancer
  • 第4章 声明式服务调用

    • Feign 声明式 HTTP 客户端
    • OpenFeign 高级特性与 Spring Cloud 集成
  • 第5章 服务容错与熔断

    • Resilience4j 服务容错与熔断
    • Sentinel 流量控制与熔断降级
  • 第6章 配置中心

    • Spring Cloud Config 配置中心
  • 第7章 API 网关

    • Spring Cloud Gateway 现代化 API 网关
    • Zuul 网关(已进入维护模式)
  • 第8章 消息驱动的微服务

    • Spring Cloud Stream 消息驱动的微服务
  • 第9章 分布式追踪与监控

    • Sleuth + Zipkin 分布式链路追踪
  • 第10章 最佳实践与面试考点

    • Spring Cloud 最佳实践与面试考点

Spring Cloud LoadBalancer

导学

"Ribbon 进入维护模式了,CTO 大翔让我评估一下替代方案。"白歌在周会上说。

小崔有点紧张:"Ribbon 我用得挺好的啊,为什么要换?"

白歌解释道:"Ribbon 基于阻塞 I/O 线程模型,在高并发场景下线程开销大。Spring Cloud 官方推出的 LoadBalancer 基于 Reactor 响应式架构,是 Ribbon 的继任者。而且从 Spring Cloud 2020.0.x 开始,如果项目中不显式引入 Ribbon,默认就会使用 LoadBalancer。"


定位与问题场景

Ribbon 的核心问题:基于 Servlet 阻塞模型,每个请求占用一个线程,在微服务间高频调用场景下线程上下文切换开销大。Spring Cloud LoadBalancer 通过响应式架构解决了这个问题:

维度RibbonSpring Cloud LoadBalancer
线程模型阻塞(Servlet)响应式(Reactor)
维护状态已进入维护模式官方活跃维护
Spring 集成通过拦截器适配原生 Spring 生态
自定义策略实现 IRule 接口实现 ReactorLoadBalancer
缓存无内置缓存内置 LoadBalancerCacheManager

Spring Cloud LoadBalancer 核心原理

架构对比

核心组件

组件职责
ReactorLoadBalancer<T>响应式负载均衡器接口,T 为实例类型
RoundRobinLoadBalancer默认轮询实现
RandomLoadBalancer随机实现
ServiceInstanceListSupplier响应式获取服务实例列表(从 DiscoveryClient)
LoadBalancerClientFactory创建和管理每个服务的 LoadBalancer 实例

负载均衡流程


完整示例:飞翔科技订单服务迁移到 LoadBalancer

场景描述

将订单服务从 Ribbon 迁移到 Spring Cloud LoadBalancer,保持相同的负载均衡能力。

操作前后对比:

维度迁移前(Ribbon)迁移后(LoadBalancer)
依赖spring-cloud-starter-netflix-ribbonspring-cloud-starter-loadbalancer
配置方式Ribbon 专属配置Spring 原生 @Bean
调用方式RestTemplate + @LoadBalancedRestTemplate + @LoadBalanced(兼容)
自定义策略IRuleReactorLoadBalancer

步骤一:依赖切换

<!-- 移除 Ribbon -->
<!-- <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency> -->

<!-- 使用 LoadBalancer -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

步骤二:RestTemplate 配置(向后兼容)

@Configuration
public class RestTemplateConfig {
    @Bean
    @LoadBalanced   // LoadBalancer 拦截器自动生效
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

无需修改任何调用代码——RestTemplate + @LoadBalanced 注解保持不变。

步骤三:自定义随机负载均衡策略

public class CustomRandomLoadBalancer implements ReactorServiceInstanceLoadBalancer {

    private final String serviceId;
    private final ObjectProvider<ServiceInstanceListSupplier> suppliers;

    public CustomRandomLoadBalancer(
            String serviceId,
            ObjectProvider<ServiceInstanceListSupplier> suppliers) {
        this.serviceId = serviceId;
        this.suppliers = suppliers;
    }

    @Override
    public Mono<Response<ServiceInstance>> choose(Request request) {
        ServiceInstanceListSupplier supplier = suppliers.getIfAvailable();
        return supplier.get(request)
                .collectList()
                .map(instances -> {
                    if (instances.isEmpty()) {
                        return new EmptyResponse();
                    }
                    // 随机选择一个实例
                    int index = ThreadLocalRandom.current()
                            .nextInt(instances.size());
                    return new DefaultResponse(instances.get(index));
                });
    }
}

@Configuration
public class CustomLoadBalancerConfig {

    @Bean
    public ReactorLoadBalancer<ServiceInstance> customLoadBalancer(
            Environment environment,
            LoadBalancerClientFactory factory) {
        String serviceId = environment.getProperty(
                LoadBalancerClientFactory.PROPERTY_NAME);
        return new CustomRandomLoadBalancer(
                serviceId,
                factory.getLazyProvider(serviceId, ServiceInstanceListSupplier.class)
        );
    }
}

步骤四:响应式 WebClient 调用(高级用法)

@RestController
public class OrderController {
    @Autowired
    private WebClient.Builder webClientBuilder;

    // LoadBalancer + WebClient(响应式,推荐新项目使用)
    @GetMapping("/order/check-stock-reactive/{productId}")
    public Mono<Map> checkStockReactive(@PathVariable Long productId) {
        return webClientBuilder.build()
                .get()
                .uri("http://FEIXIANG-INVENTORY-SERVICE/inventory/" + productId)
                .retrieve()
                .bodyToMono(Map.class);
    }
}

易错场景

1. Spring Cloud 2020.x 之前引入 LoadBalancer 导致 Ribbon 失效

Spring Cloud Hoxton 及更早版本默认使用 Ribbon。如果手动引入 spring-cloud-starter-loadbalancer,需要排除 Ribbon 的自动配置:

spring:
  cloud:
    loadbalancer:
      ribbon:
        enabled: false

2. 自定义 LoadBalancer 未注册导致 NoInstanceAvailableException

自定义的 ReactorLoadBalancer Bean 必须被 Spring 容器管理,且 Bean Name 必须遵循约定:

@LoadBalancerClient(
    name = "FEIXIANG-INVENTORY-SERVICE",
    configuration = CustomLoadBalancerConfig.class
)

3. WebClient 与 RestTemplate 混用时 LoadBalancer 不一致

@LoadBalanced 注解对 RestTemplate 生效,但不影响 WebClient。使用 WebClient 时需通过 @LoadBalanced WebClient.Builder 自动注入。

4. 滥用缓存导致扩缩容感知延迟

LoadBalancer 默认启用缓存,实例列表不会每次都去注册中心拉取。如果频繁扩缩容,需调整缓存 TTL:

spring:
  cloud:
    loadbalancer:
      cache:
        ttl: 10s        # 缓存 10 秒
        capacity: 256

面试考点

Spring Cloud LoadBalancer 与 Ribbon 的区别?

  1. LoadBalancer 基于 Reactor 响应式架构,Ribbon 基于阻塞线程模型
  2. LoadBalancer 是 Spring 官方维护,Ribbon 已停更
  3. LoadBalancer 与 Spring 生态(WebClient、Reactive)深度集成
  4. LoadBalancer 内置缓存支持(基于 Caffeine),Ribbon 无内置缓存
  5. Spring Cloud 2020.0.x 起默认使用 LoadBalancer

Spring Cloud LoadBalancer 的工作流程?

① 请求到达 @LoadBalanced RestTemplate 或 WebClient;② 拦截器从请求 URL 中提取服务名;③ LoadBalancerClientFactory 根据服务名获取对应的 ReactorLoadBalancer;④ ServiceInstanceListSupplier 从 DiscoveryClient 响应式获取实例列表;⑤ ReactorLoadBalancer.choose() 根据策略选择一个实例;⑥ 替换 URL 中的服务名为实际 IP:Port,发起真实请求。

如何在 LoadBalancer 中实现 Nacos 权重策略?

Nacos 实例元数据中包含 nacos.weight,可以自定义 ReactorLoadBalancer 读取该权重值,实现加权随机或加权轮询。Spring Cloud Alibaba 已内置 Nacos 权重负载均衡支持,引入 spring-cloud-starter-alibaba-nacos-discovery 后自动生效。


小结

Spring Cloud LoadBalancer 是 Ribbon 的官方继任者,基于响应式架构提供了更现代的负载均衡能力。迁移成本极低——RestTemplate + @LoadBalanced 注解完全兼容,自定义策略也只需实现 ReactorLoadBalancer 接口。名字找到了、实例选好了,下一步就是如何优雅地写调用代码——声明式 HTTP 客户端 Feign 登场。

上一页
Ribbon 客户端负载均衡