微服务之Spring Cloud LoadBalancer

Spring Cloud LoadBalancer(SCLB)核心知识梳理

一、核心定位

Spring 官方推出的 客户端负载均衡器,自 Spring Cloud 2020.0.0 起,替代 Netflix Ribbon 成为默认方案,适配微服务架构,轻量、响应式、持续维护。

核心逻辑:服务消费者本地缓存服务列表,按策略选择实例直接调用,无中间转发,避免中心单点。

二、核心优势(对比 Ribbon)

  • 官方原生:Spring 团队维护,持续更新,无第三方依赖包袱

  • 响应式优先:基于 Project Reactor,原生支持 WebFlux、Spring Gateway

  • 轻量级:仅保留核心LB能力,启动快、占用资源少

  • 健康检查:内置主动探测(默认 /actuator/health),自动剔除故障节点

  • 配置灵活:支持全局/服务级配置,与 Spring Boot 配置体系无缝融合

三、核心架构与组件

  1. ReactiveLoadBalancer:核心接口,负责选择服务实例

  2. 核心方法:Mono<Response> choose(Request)

  3. 核心实现:RoundRobinLoadBalancer(默认)、RandomLoadBalancer

  4. ServiceInstanceListSupplier:从注册中心(Nacos/Eureka)获取、过滤、缓存服务实例列表,仅返回 UP 状态实例

  5. LoadBalancerClientFactory:工厂类,为每个服务创建独立的 LoadBalancer 实例

  6. @LoadBalanced:注解,为 RestTemplate / WebClient 开启负载均衡拦截,自动解析服务名

四、工作流程(4步)

  1. 拉取列表:通过 DiscoveryClient 从注册中心拉取服务实例,本地缓存(默认35s过期)

  2. 健康过滤:剔除 DOWN/不可用实例,筛选出可用实例列表

  3. 策略选择:按配置的负载均衡策略,选择一个目标实例

  4. 请求转发:将服务名替换为实例的 IP:Port,发起直接调用

五、内置负载均衡策略

策略类

核心说明

适用场景

RoundRobinLoadBalancer(默认)

原子计数器轮询,线程安全,均匀分发

实例性能相近、需均匀分配流量

RandomLoadBalancer

基于 ThreadLocalRandom 随机选择,简单高效

无状态服务、大流量场景,追求简单均衡

六、快速集成与使用(Spring Boot + Nacos)

  1. 依赖配置(Maven)

org.springframework.cloud spring-cloud-starter-loadbalancer com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery

  1. 配置类(开启负载均衡)

方式1:RestTemplate(阻塞式,适用于传统Spring MVC)

@Configuration

public class RestTemplateConfig {

@Bean

@LoadBalanced // 关键:开启负载均衡拦截

public RestTemplate restTemplate() {

return new RestTemplate();

}

}

方式2:WebClient(响应式,推荐,适用于WebFlux)

@Configuration

public class WebClientConfig {

@Bean

@LoadBalanced

public WebClient.Builder webClientBuilder() {

return WebClient.builder();

}

}

  1. 服务调用(用服务名替代IP)

RestTemplate 调用

@Service

public class OrderService {

@Autowired

private RestTemplate restTemplate;

复制代码
// 直接使用服务名(user-service),LB自动解析为IP:Port
public String getUser(Long userId) {
    return restTemplate.getForObject("http://user-service/user/" + userId, String.class);
}

}

WebClient 响应式调用

@Service

public class ReactiveOrderService {

@Autowired

private WebClient.Builder webClientBuilder;

复制代码
public Mono<String> getUser(Long userId) {
    return webClientBuilder.build()
            .get()
            .uri("http://user-service/user/" + userId)
            .retrieve()
            .bodyToMono(String.class);
}

}

七、OpenFeign 与 SCLB 集成配置(微服务调用专属)

微服务间基于 OpenFeign 调用时,无需额外配置 SCLB 负载均衡核心逻辑(Spring Cloud 2020.0.0+ 已默认集成 SCLB 替代 Ribbon),但需完成 OpenFeign 基础配置 + 集成依赖,确保负载均衡、重试、超时等功能正常生效。

  1. 核心依赖配置(Maven)

需同时引入 OpenFeign 和 SCLB 依赖(Nacos 依赖中虽集成 SCLB,但单独引入可避免调用异常),无需额外引入 Ribbon 依赖(避免冲突):
org.springframework.cloud spring-cloud-starter-openfeign org.springframework.cloud spring-cloud-starter-loadbalancer com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery org.springframework.retry spring-retry

  1. 启动类开启 OpenFeign(核心配置)

在服务消费者启动类上添加 @EnableFeignClients 注解,开启 OpenFeign 客户端功能,自动扫描 Feign 接口:

@SpringBootApplication

@EnableFeignClients // 开启OpenFeign客户端

@EnableDiscoveryClient // 开启服务发现(Nacos/Eureka)

public class ConsumerApplication {

public static void main(String[] args) {

SpringApplication.run(ConsumerApplication.class, args);

}

}

  1. 定义 Feign 接口(服务调用核心)

Feign 接口中通过 @FeignClient(name = "服务名") 绑定目标服务,接口方法与服务提供者保持一致,SCLB 会自动对该接口的调用进行负载均衡:

// 绑定目标服务(服务名与注册中心一致,如user-service)

@FeignClient(name = "user-service")

public interface UserFeignClient {

// 接口方法与服务提供者完全一致(请求方式、路径、参数)

@GetMapping("/user/{id}")

String getUserById(@PathVariable("id") Long id);

复制代码
@PostMapping("/user/save")
Boolean saveUser(@RequestBody User user);

}

  1. 关键补充配置(application.yml)

需配置 Feign 自身超时、日志,以及 SCLB 负载均衡、重试策略(与 SCLB 全局配置兼容),确保调用稳定:

spring:

cloud:

SCLB 配置(与前文全局配置一致,无需重复,可补充Feign专属适配)

loadbalancer:

retry:

enabled: true # 开启重试(配合Feign调用失败重试)

max-retries-on-same-service-instance: 0 # 同一实例不重试

max-retries-on-next-service-instance: 1 # 切换实例重试1次

nacos:

enabled: true # 开启Nacos与SCLB适配(Nacos注册中心必配)

nacos:

discovery:

server-addr: nacos-node1:8848,nacos-node2:8848 # 注册中心地址

Feign 专属配置

feign:

client:

config:

default: # 全局配置(所有Feign接口生效)

connectTimeout: 1000 # Feign连接超时(需与SCLB超时匹配)

readTimeout: 2000 # Feign读取超时

loggerLevel: basic # 日志级别(basic:仅记录请求/响应状态)

启用SCLB负载均衡(默认已启用,无需手动开启,防止误配Ribbon)

loadbalancer:

enabled: true

配合重试:启用Spring Retry(需引入spring-retry依赖)

retry:

enabled: true

  1. 特殊场景配置
  • 指定服务负载均衡策略:若某一Feign接口(如pay-service)需单独配置SCLB策略,可沿用SCLB服务级配置,Feign会自动继承该策略。

  • Feign 日志精细化:如需调试,可将 loggerLevel 设为 full,同时配置对应Feign接口的日志级别为DEBUG。

  • 避免 Ribbon 冲突:若项目中存在Ribbon依赖,需排除Ribbon,确保SCLB生效(OpenFeign默认优先使用SCLB)。

  • 响应式 Feign:若使用 WebFlux,可引入 spring-cloud-starter-openfeign-reactive 依赖,适配SCLB响应式负载均衡。

补充说明:OpenFeign 会自动集成 SCLB,无需在 Feign 接口或配置类中添加 @LoadBalanced 注解,仅需保证 SCLB 依赖存在且配置正确即可,底层由 FeignBlockingLoadBalancerClient 实现负载均衡调用。

八、核心配置(application.yml)

  1. 全局配置

spring:

cloud:

loadbalancer:

缓存配置(默认开启,提升性能)

cache:

enabled: true

ttl: 35s # 缓存过期时间(默认35s)

capacity: 256 # 最大缓存实例数

健康检查配置

health-check:

path:

default: /actuator/health # 默认健康检查路径

interval: 10s # 健康检查间隔

超时配置

client:

connect-timeout: 1000 # 连接超时(ms)

read-timeout: 2000 # 读取超时(ms)

重试配置

retry:

enabled: true # 开启重试

max-retries-on-same-service-instance: 0 # 同一实例不重试

max-retries-on-next-service-instance: 1 # 切换实例重试1次

饥饿加载(解决首次调用慢)

eager-load:

enabled: true

clients: user-service,order-service # 预加载的服务名

  1. 服务级配置(指定单个服务策略)

// 全局配置类,指定user-service使用轮询策略

@Configuration

@LoadBalancerClient(name = "user-service", configuration = UserServiceLBConfig.class)

public class GlobalLBConfig {}

// 单个服务的负载均衡策略配置

class UserServiceLBConfig {

@Bean

public ReactorLoadBalancer roundRobinLoadBalancer(

Environment env, LoadBalancerClientFactory factory) {

String serviceId = env.getProperty("loadbalancer.client.name");

return new RoundRobinLoadBalancer(factory.getLazyProvider(serviceId, ServiceInstance.class), serviceId);

}

}

九、自定义负载均衡策略(加权轮询示例)

// 1. 自定义加权轮询策略

public class WeightedLoadBalancer implements ReactiveLoadBalancer {

private final String serviceId;

private final Supplier<Mono<List>> instanceSupplier;

复制代码
// 构造方法:注入实例供应器和服务ID
public WeightedLoadBalancer(Supplier<Mono<List<ServiceInstance>>> supplier, String serviceId) {
    this.serviceId = serviceId;
    this.instanceSupplier = supplier;
}

@Override
public Mono<Response<ServiceInstance>> choose(Request request) {
    return instanceSupplier.get()
            .map(instances -> {
                if (instances.isEmpty()) {
                    return new EmptyResponse(); // 无可用实例
                }
                // 核心:根据实例元数据中的weight属性选择
                return new DefaultResponse(selectByWeight(instances));
            });
}

// 加权选择逻辑:遍历实例,根据权重分配
private ServiceInstance selectByWeight(List<ServiceInstance> instances) {
    int totalWeight = instances.stream()
            .mapToInt(instance -> Integer.parseInt(instance.getMetadata().getOrDefault("weight", "1")))
            .sum();
    int randomWeight = new Random().nextInt(totalWeight) + 1;
    int currentWeight = 0;
    for (ServiceInstance instance : instances) {
        currentWeight += Integer.parseInt(instance.getMetadata().getOrDefault("weight", "1"));
        if (currentWeight >= randomWeight) {
            return instance;
        }
    }
    return instances.get(0); // 兜底:返回第一个实例
}

}

// 2. 注册自定义策略(指定pay-service使用加权策略)

@Configuration

@LoadBalancerClient(name = "pay-service", configuration = WeightedLBConfig.class)

public class CustomLBConfig {}

class WeightedLBConfig {

@Bean

public ReactorLoadBalancer weightedLoadBalancer(

Environment env, LoadBalancerClientFactory factory) {

String serviceId = env.getProperty("loadbalancer.client.name");

return new WeightedLoadBalancer(factory.getLazyProvider(serviceId, ServiceInstance.class), serviceId);

}

}

十、生产最佳实践

  1. 策略选型:

  2. 通用场景:RoundRobinLoadBalancer(默认,均匀分发)

  3. 异构实例(性能差异大):自定义加权策略

  4. 无状态、大流量:RandomLoadBalancer

  5. 性能优化:开启缓存、饥饿加载,减少注册中心拉取频率

  6. 高可用保障:启用健康检查、重试机制,自动剔除故障节点

  7. 超时控制:合理配置连接/读取超时,避免长时间阻塞

  8. 服务隔离:为不同服务配置独立策略,避免相互影响

  9. OpenFeign 适配:Feign超时与SCLB超时保持一致,开启重试时需引入spring-retry依赖,避免重复配置冲突。

十一、面试高频考点

  1. Spring Cloud LoadBalancer 与 Ribbon 的核心区别?

  2. LoadBalancer:Spring 官方、响应式、轻量、持续维护,支持 WebFlux

  3. Ribbon:Netflix 开源、阻塞式、已停更、依赖重,不支持响应式

  4. SCLB 的默认负载均衡策略是什么?RoundRobinLoadBalancer(轮询)

  5. SCLB 如何实现健康检查?定期调用实例的 /actuator/health 接口,标记 DOWN 实例并剔除

  6. @LoadBalanced 注解的作用?拦截 RestTemplate/WebClient 的请求,将服务名解析为具体的 IP:Port

  7. 如何解决 SCLB 首次调用慢的问题?开启饥饿加载(eager-load),预加载指定服务的实例列表

  8. OpenFeign 与 SCLB 集成需要单独配置负载均衡吗?无需单独配置,引入依赖并开启@EnableFeignClients,Feign会自动集成SCLB实现负载均衡。

十二、总结

Spring Cloud LoadBalancer 是 现代微服务客户端负载均衡的首选方案,轻量、可靠、响应式、易扩展,完美替代停更的 Ribbon。新项目必用,老项目建议逐步迁移,适配 Spring Cloud 新版本生态。微服务间基于 OpenFeign 调用时,核心是完成 Feign 基础配置与依赖引入,SCLB 会自动适配,无需额外配置负载均衡核心逻辑,配合合理的超时、重试配置,即可实现稳定的服务调用。

相关推荐
杜子不疼.2 小时前
AI Agent 智能体开发入门:AutoGen 多智能体协作实战教程
java·人工智能·spring
樽酒ﻬق2 小时前
构筑容器化基石:Docker 稳定版本抉择、极速安装与配置全解
java·docker·运维开发
星辰_mya2 小时前
深度全面学习负载均衡Ribbon/Spring Cloud LoadBalancer
后端·spring cloud·面试·负载均衡·架构师
weisian1512 小时前
Java并发编程--29-分布式ID的6种方案:从单机到分库分表的“身份证”设计
java·分布式·雪花算法·美团leaf·百度uid
美式请加冰2 小时前
最短路径问题
java·数据结构·算法
小江的记录本2 小时前
【JEECG Boot】 JEECG Boot 数据字典管理——六大核心功能(内含:《JEECG Boot 数据字典开发速查清单》)
java·前端·数据库·spring boot·后端·spring·mybatis
小江的记录本2 小时前
【JEECG Boot】 JEECG Boot——Online表单 系统性知识体系全解
java·前端·spring boot·后端·spring·低代码·mybatis
都说名字长不会被发现2 小时前
Spring 线程池最佳实践:如何优雅管理多线程任务
java·spring·线程池·并发编程
wok1572 小时前
WebMVC 和 WebFlux 架构选型
java·spring·架构·mvc