Ribbon 与 LoadBalancer:客户端负载均衡
负载均衡是微服务架构中不可或缺的一环。当一个服务有多个实例时,负载均衡器决定将请求发送给哪个实例。在 Spring Cloud 生态中,经历了从 Ribbon 到 Spring Cloud LoadBalancer 的演进。
一、为什么需要客户端负载均衡?
服务端负载均衡(Nginx):
客户端 → [Nginx 中心节点] → 实例1 / 实例2 / 实例3
特点:客户端不知道后端实例,Nginx 是单点瓶颈
客户端负载均衡(Ribbon/LoadBalancer):
客户端 → 从注册中心拉取实例列表 → 自己选一个 → 直连实例
特点:无中心节点,更灵活,微服务内部调用标配在微服务架构中,服务间调用(如订单服务调用库存服务)走的是内网,不需要经过 Nginx。客户端负载均衡让调用方自己从注册中心获取实例列表并选择,省去了中心化负载均衡器的瓶颈。
二、Ribbon:Netflix 时代的经典
2.1 Ribbon 是什么
Ribbon 是 Netflix 开源的客户端负载均衡器,曾经是 Spring Cloud 生态中服务调用的标配。它内嵌在 Feign 和 RestTemplate 中,自动为服务调用提供负载均衡能力。
2.2 Ribbon 核心组件
| 组件 | 接口 | 说明 |
|---|---|---|
| ServerList | 获取服务实例列表 | 从注册中心(Eureka/Nacos)拉取 |
| IRule | 负载均衡策略 | 轮询、随机、加权、最小连接数等 |
| IPing | 健康检查 | 判断实例是否存活 |
| ServerListFilter | 实例过滤 | 过滤掉不健康的实例 |
| ILoadBalancer | 协调器 | 整合以上组件,对外提供 chooseServer() |
2.3 内置负载均衡策略
| 策略类 | 说明 |
|---|---|
RoundRobinRule | 轮询,依次选择(默认) |
RandomRule | 随机选择 |
WeightedResponseTimeRule | 按响应时间加权,响应越快权重越高 |
BestAvailableRule | 选择并发请求最少的实例 |
RetryRule | 失败后重试,换一个实例 |
AvailabilityFilteringRule | 过滤掉熔断或高并发的实例 |
ZoneAvoidanceRule | 按区域就近选择 |
2.4 Ribbon 的现状
2020 年,Netflix 宣布 Ribbon 进入维护模式(不再添加新功能,只修 Bug)。Spring Cloud 官方随即推出了替代方案——Spring Cloud LoadBalancer。目前新项目已不再推荐使用 Ribbon。
三、Spring Cloud LoadBalancer:官方替代品
3.1 与 Ribbon 的对比
| 维度 | Ribbon | Spring Cloud LoadBalancer |
|---|---|---|
| 维护方 | Netflix(已停维) | Spring 官方(活跃) |
| 编程模型 | 阻塞式 | 响应式(Reactive) |
| 性能 | 一般 | 更好(非阻塞) |
| 与 Spring Cloud 集成 | 原生(旧版) | 原生(新版) |
| 自定义策略 | 实现 IRule 接口 | 实现 ReactorLoadBalancer 接口 |
| Spring 官方推荐 | 否 | 是 |
3.2 工作原理
1. 服务启动时,注册到 Nacos
│
▼
2. @FeignClient 标注的服务调用
│
▼
3. Feign 拦截调用,委托给 LoadBalancer
│
▼
4. LoadBalancer 从 Nacos 获取目标服务的实例列表
│
▼
5. 根据负载均衡策略选择一个实例
│
▼
6. 构造 HTTP 请求,发送到选中的实例
│
▼
7. 如果调用失败,根据重试策略决定是否换一个实例重试3.3 内置策略
| 策略 | 说明 | 适用场景 |
|---|---|---|
| RoundRobinLoadBalancer | 轮询(默认) | 实例性能一致 |
| RandomLoadBalancer | 随机选择 | 简单场景 |
| NacosLoadBalancer | 基于 Nacos 权重 | 使用 Nacos 注册中心时 |
3.4 配置示例
spring:
cloud:
loadbalancer:
retry:
enabled: true # 开启重试,失败后换实例
cache:
enabled: true # 开启实例列表缓存
ttl: 35s # 缓存过期时间
nacos:
enabled: true # 启用 Nacos 权重策略3.5 自定义策略
@Configuration
public class CustomLoadBalancerConfig {
@Bean
public ReactorLoadBalancer<ServiceInstance> customLoadBalancer(
Environment env, LoadBalancerClientFactory factory) {
String name = env.getProperty("loadbalancer.client.name");
return new RoundRobinLoadBalancer(
factory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
}
}四、Ribbon → LoadBalancer 迁移要点
如果你的项目从旧版 Spring Cloud 升级,需要注意以下变化:
| 迁移项 | Ribbon 写法 | LoadBalancer 写法 |
|---|---|---|
| 依赖 | spring-cloud-starter-netflix-ribbon | spring-cloud-starter-loadbalancer(已内置) |
| 策略配置 | order-service.ribbon.NFLoadBalancerRuleClassName | @LoadBalancerClient 注解 |
| 自定义策略 | implements IRule | implements ReactorLoadBalancer |
| 重试配置 | ribbon.MaxAutoRetries | spring.cloud.loadbalancer.retry.enabled |
五、面试要点
Q:Ribbon 和 Spring Cloud LoadBalancer 的区别?
- Ribbon 是 Netflix 开源,已停维;LoadBalancer 是 Spring 官方,活跃维护
- Ribbon 是阻塞式 IO;LoadBalancer 基于响应式编程,非阻塞,性能更好
- Ribbon 策略更丰富(7 种内置);LoadBalancer 策略较少但够用,且支持自定义
- 新项目直接用 LoadBalancer,旧项目在使用 Ribbon 也无需急于迁移
Q:Feign 中如何选择负载均衡策略?
Feign 默认使用 LoadBalancer 的轮询策略。如需自定义,通过 @LoadBalancerClient 注解指定配置类,或直接配置 spring.cloud.loadbalancer.nacos.enabled=true 启用 Nacos 权重策略。
Q:客户端负载均衡 vs 服务端负载均衡,微服务中为什么用客户端?
客户端负载均衡去掉了中心化 LB 的瓶颈,调用方直连目标实例,减少一次网络跳转。而且客户端知道所有实例的状态,可以做更智能的负载均衡决策(如最小连接数)。服务端负载均衡(Nginx)更适合对外暴露的 API 入口。