Spring Cloud LoadBalancer(SCLB)核心知识梳理
一、核心定位
Spring 官方推出的 客户端负载均衡器,自 Spring Cloud 2020.0.0 起,替代 Netflix Ribbon 成为默认方案,适配微服务架构,轻量、响应式、持续维护。
核心逻辑:服务消费者本地缓存服务列表,按策略选择实例直接调用,无中间转发,避免中心单点。
二、核心优势(对比 Ribbon)
-
官方原生:Spring 团队维护,持续更新,无第三方依赖包袱
-
响应式优先:基于 Project Reactor,原生支持 WebFlux、Spring Gateway
-
轻量级:仅保留核心LB能力,启动快、占用资源少
-
健康检查:内置主动探测(默认 /actuator/health),自动剔除故障节点
-
配置灵活:支持全局/服务级配置,与 Spring Boot 配置体系无缝融合
三、核心架构与组件
-
ReactiveLoadBalancer:核心接口,负责选择服务实例
-
核心方法:Mono<Response> choose(Request)
-
核心实现:RoundRobinLoadBalancer(默认)、RandomLoadBalancer
-
ServiceInstanceListSupplier:从注册中心(Nacos/Eureka)获取、过滤、缓存服务实例列表,仅返回 UP 状态实例
-
LoadBalancerClientFactory:工厂类,为每个服务创建独立的 LoadBalancer 实例
-
@LoadBalanced:注解,为 RestTemplate / WebClient 开启负载均衡拦截,自动解析服务名
四、工作流程(4步)
-
拉取列表:通过 DiscoveryClient 从注册中心拉取服务实例,本地缓存(默认35s过期)
-
健康过滤:剔除 DOWN/不可用实例,筛选出可用实例列表
-
策略选择:按配置的负载均衡策略,选择一个目标实例
-
请求转发:将服务名替换为实例的 IP:Port,发起直接调用
五、内置负载均衡策略
策略类
核心说明
适用场景
RoundRobinLoadBalancer(默认)
原子计数器轮询,线程安全,均匀分发
实例性能相近、需均匀分配流量
RandomLoadBalancer
基于 ThreadLocalRandom 随机选择,简单高效
无状态服务、大流量场景,追求简单均衡
六、快速集成与使用(Spring Boot + Nacos)
- 依赖配置(Maven)
org.springframework.cloud spring-cloud-starter-loadbalancer com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery
- 配置类(开启负载均衡)
方式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();
}
}
- 服务调用(用服务名替代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 基础配置 + 集成依赖,确保负载均衡、重试、超时等功能正常生效。
- 核心依赖配置(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
- 启动类开启 OpenFeign(核心配置)
在服务消费者启动类上添加 @EnableFeignClients 注解,开启 OpenFeign 客户端功能,自动扫描 Feign 接口:
@SpringBootApplication
@EnableFeignClients // 开启OpenFeign客户端
@EnableDiscoveryClient // 开启服务发现(Nacos/Eureka)
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
- 定义 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);
}
- 关键补充配置(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
- 特殊场景配置
-
指定服务负载均衡策略:若某一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)
- 全局配置
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 # 预加载的服务名
- 服务级配置(指定单个服务策略)
// 全局配置类,指定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);
}
}
十、生产最佳实践
-
策略选型:
-
通用场景:RoundRobinLoadBalancer(默认,均匀分发)
-
异构实例(性能差异大):自定义加权策略
-
无状态、大流量:RandomLoadBalancer
-
性能优化:开启缓存、饥饿加载,减少注册中心拉取频率
-
高可用保障:启用健康检查、重试机制,自动剔除故障节点
-
超时控制:合理配置连接/读取超时,避免长时间阻塞
-
服务隔离:为不同服务配置独立策略,避免相互影响
-
OpenFeign 适配:Feign超时与SCLB超时保持一致,开启重试时需引入spring-retry依赖,避免重复配置冲突。
十一、面试高频考点
-
Spring Cloud LoadBalancer 与 Ribbon 的核心区别?
-
LoadBalancer:Spring 官方、响应式、轻量、持续维护,支持 WebFlux
-
Ribbon:Netflix 开源、阻塞式、已停更、依赖重,不支持响应式
-
SCLB 的默认负载均衡策略是什么?RoundRobinLoadBalancer(轮询)
-
SCLB 如何实现健康检查?定期调用实例的 /actuator/health 接口,标记 DOWN 实例并剔除
-
@LoadBalanced 注解的作用?拦截 RestTemplate/WebClient 的请求,将服务名解析为具体的 IP:Port
-
如何解决 SCLB 首次调用慢的问题?开启饥饿加载(eager-load),预加载指定服务的实例列表
-
OpenFeign 与 SCLB 集成需要单独配置负载均衡吗?无需单独配置,引入依赖并开启@EnableFeignClients,Feign会自动集成SCLB实现负载均衡。
十二、总结
Spring Cloud LoadBalancer 是 现代微服务客户端负载均衡的首选方案,轻量、可靠、响应式、易扩展,完美替代停更的 Ribbon。新项目必用,老项目建议逐步迁移,适配 Spring Cloud 新版本生态。微服务间基于 OpenFeign 调用时,核心是完成 Feign 基础配置与依赖引入,SCLB 会自动适配,无需额外配置负载均衡核心逻辑,配合合理的超时、重试配置,即可实现稳定的服务调用。