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

    • 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 最佳实践与面试考点

Ribbon 客户端负载均衡

导学

"现在订单服务通过 Eureka 已经知道库存服务有 3 个实例了,"小崔问白歌,"但每次调用时,我怎么决定发给哪个实例?总不会永远只打第一个吧?"

白歌在白板上画了一张图:"这就是客户端负载均衡要解决的问题。Netflix Ribbon 是目前最成熟的方案——虽然 Spring Cloud 2020.x 开始推荐 LoadBalancer,但 Ribbon 的设计思想是所有负载均衡组件的基石,理解它对后续学习至关重要。"


定位与问题场景

Eureka 返回了实例列表(如 192.168.1.10:8081, 192.168.1.11:8081, 192.168.1.12:8081),选哪个?怎么选?选了之后是否要重试?

这就是**客户端负载均衡(Client-Side Load Balancing)**的职责:

客户端负载均衡 vs 服务端负载均衡:

维度客户端负载均衡(Ribbon)服务端负载均衡(Nginx)
负载均衡位置消费者进程内独立进程/设备
实例感知自动从注册中心获取手动配置 upstream
网络跳数1 跳(消费者 → 提供者)2 跳(消费者 → LB → 提供者)
灵活性可按业务定制策略通用策略

Ribbon 核心原理

架构与组件

核心流程:

  1. ServerList:定时从 Eureka 拉取实例列表
  2. ServerListFilter:按条件过滤(如仅保留同 Zone 的实例)
  3. IPing:心跳检测,剔除不可达实例
  4. IRule:根据策略从剩余列表中选择一个实例

IRule:七种内置负载均衡策略

策略类名工作原理
轮询RoundRobinRule按顺序循环选择
随机RandomRule随机选择
加权响应时间WeightedResponseTimeRule响应越快权重越高
可用性过滤AvailabilityFilteringRule过滤掉断路器跳闸、高并发的实例
最小并发BestAvailableRule选择并发请求数最小的实例
区域感知ZoneAvoidanceRule默认策略,优先同 Zone + 可用性过滤
重试RetryRule在指定时间内轮询重试

完整示例:飞翔科技订单服务负载均衡

场景描述

库存服务有 3 个实例,订单服务通过 Ribbon 实现负载均衡调用。

操作前后对比:

维度引入 Ribbon 前引入 Ribbon 后
实例选择写死第一个 URL自动轮询 / 随机 / 加权
故障转移单点故障即不可用自动跳过失败实例
扩容感知手动修改配置自动感知新增实例

步骤一:依赖引入

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

步骤二:自定义负载均衡策略

@Configuration
public class RibbonConfig {

    @Bean
    public IRule ribbonRule() {
        // 改为加权响应时间策略(响应越快的实例获得越多请求)
        return new WeightedResponseTimeRule();
    }
}

或者更精细地为指定服务配置策略:

@Configuration
// 注意:该配置类不能被 @ComponentScan 扫描到,否则会成为全局配置
public class InventoryRibbonConfig {
    @Bean
    public IRule ribbonRule() {
        // 仅对库存服务使用随机策略
        return new RandomRule();
    }
}

@SpringBootApplication
@EnableDiscoveryClient
@RibbonClient(
    name = "FEIXIANG-INVENTORY-SERVICE",
    configuration = InventoryRibbonConfig.class
)
public class OrderServiceApplication {
    // ...
}

步骤三:订单服务调用(带重试)

@RestController
public class OrderController {
    @Autowired
    private RestTemplate restTemplate;

    // 引入 Ribbon 前:硬编码 + 手动 try-catch
    // String url = "http://192.168.1.100:8081/inventory/1001";
    // try { restTemplate.getForObject(url, Map.class); } catch (Exception e) { ... }

    // 引入 Ribbon 后:服务名 + 自动负载均衡
    @GetMapping("/order/check-stock/{productId}")
    public Map<String, Object> checkStock(@PathVariable Long productId) {
        return restTemplate.getForObject(
            "http://FEIXIANG-INVENTORY-SERVICE/inventory/" + productId,
            Map.class
        );
    }
}

步骤四:重试配置

feixiang-inventory-service:
  ribbon:
    # 同一实例最大重试次数
    MaxAutoRetries: 1
    # 其他实例最大重试次数
    MaxAutoRetriesNextServer: 2
    # 是否所有操作都重试(GET 安全,POST 需谨慎)
    OkToRetryOnAllOperations: false
    # 连接超时
    ConnectTimeout: 1000
    # 读取超时
    ReadTimeout: 3000

步骤五:验证负载均衡

启动 3 个库存服务实例(端口 8081 / 8082 / 8083),连续调用 9 次:

for i in {1..9}; do curl -s http://localhost:8080/order/check-stock/1001 | jq .servicePort; done

典型输出(轮询策略下):

8081, 8082, 8083, 8081, 8082, 8083, 8081, 8082, 8083

易错场景

1. Ribbon 超时时间 < Hystrix 超时时间

Ribbon 的 ConnectTimeout + ReadTimeout 如果大于 Hystrix 的超时时间,Hystrix 熔断器会先触发,导致 Ribbon 重试机制完全失效。正确配置:

Hystrix Timeout > (Ribbon ConnectTimeout + ReadTimeout) × (MaxAutoRetries + 1) × (MaxAutoRetriesNextServer + 1)

2. 饥饿加载导致首次调用超时

Ribbon 默认懒加载,首次调用时才初始化负载均衡器,可能触发超时:

ribbon:
  eager-load:
    enabled: true
    clients: feixiang-inventory-service,feixiang-payment-service

3. POST 请求重试造成重复扣款

# ❌ 危险配置:所有操作(含 POST)都重试
feixiang-inventory-service.ribbon.OkToRetryOnAllOperations: true
# ✅ 安全配置:仅幂等的 GET 操作重试
feixiang-inventory-service.ribbon.OkToRetryOnAllOperations: false

4. Ribbon 配置类被全局扫描

@RibbonClient 引用的配置类不能被 @ComponentScan 或 @SpringBootApplication 扫描到,否则会成为所有 Ribbon Client 的全局配置。配置类应放在独立包中。


面试考点

Ribbon 的负载均衡发生在哪一层?

Ribbon 是客户端负载均衡,负载均衡逻辑运行在服务消费者的进程内。当 RestTemplate 发起调用时,Ribbon 拦截请求,根据从注册中心获取的实例列表和配置的策略,选择一个实例发起真实 HTTP 请求。整个过程在消费者本地完成,不需要额外的网络跳转。

Ribbon 和 Nginx 的区别?

Ribbon 是客户端负载均衡(Consumer 进程内),Nginx 是服务端负载均衡(独立进程/设备)。Nginx 需要额外一跳网络开销,但可以集中管理;Ribbon 没有额外网络跳数,但策略逻辑分散在各消费者中。微服务架构中二者通常配合使用:Nginx 做外部流量入口的负载均衡,Ribbon 做内部服务间调用的负载均衡。

Ribbon 的默认策略是什么?为什么?

默认策略是 ZoneAvoidanceRule(区域感知),复合了可用性过滤。设计意图:优先选择同 Zone(同一机房/可用区)的实例,减少跨机房网络延迟;同时过滤掉断路器跳闸或并发过高的实例,保证调用成功率。

Ribbon 重试机制的注意事项?

  • 仅对幂等操作(GET/HEAD/OPTIONS)重试,POST/PUT/DELETE 可能导致重复扣款
  • 重试总次数 = (MaxAutoRetries + 1) × (MaxAutoRetriesNextServer + 1) - 1
  • 重试超时时间必须小于上层熔断器的超时时间

小结

Ribbon 是微服务调用链的第二环:注册中心告诉你有哪些服务实例,Ribbon 决定调用哪个实例。内置的七种负载均衡策略覆盖了轮询、随机、加权等场景,配合重试机制可以实现基础的故障转移。但 Ribbon 已进入维护模式,Spring Cloud 2020.x 起官方推荐使用 Spring Cloud LoadBalancer——下一节我们将详细对比。

下一页
Spring Cloud LoadBalancer