下载工作台
Spring Cloud 微服务

负载均衡与 Resilience4j 熔断

试读上半部分 · 解锁后可读全文

第 5 章 · Spring Cloud LoadBalancer 与 Resilience4j 熔断降级

本章目标:深入 Spring Cloud LoadBalancer 实例选择策略与缓存;在 OpenFeignGateway 上集成 Resilience4j 实现熔断、限流、超时、舱壁;设计 fallback 降级返回;理解雪崩效应与半开状态;在 svc-spring-demo 中模拟 product-svc 故障时的订单创建体验。

学时建议:5~6 小时(含 2 小时故障注入实验)

前置spring-cloud-web ch01~ch04spring-boot-web ch10 异步与超时概念。


5.1 为什么需要客户端负载均衡与熔断

                    product-svc 实例
                 ┌──────┐  ┌──────┐
 order-svc ─────►│ :8082│  │ :8092│
                 └──────┘  └──────┘
                      │
            若 8082 慢/挂,仍被轮询到?
                      ▼
            LoadBalancer 选健康实例
                      +
            CircuitBreaker 快速失败 + fallback
问题组件
多实例选哪一个LoadBalancer
下游持续失败拖垮调用方CircuitBreaker 熔断
仍需有限流量试探恢复半开 Half-Open
给用户可理解响应Fallback 降级
虚构项目 svc-spring-demo;故障实验仅在本地进行,勿对共享环境注入混沌。

5.2 Spring Cloud LoadBalancer 基础

Spring Cloud 2020 起,Ribbon 已移除,默认 Spring Cloud LoadBalancer

5.2.1 与 Nacos 集成

Feign @FeignClient(name = "product-svc") 时:

  1. 从 Nacos 拉取 product-svc 实例列表
  2. LoadBalancer 按策略选一个
  3. 发起 HTTP 请求

无需额外 @LoadBalanced 注解(Feign 内置);RestTemplate 需:

@Bean
@LoadBalanced
public RestTemplate restTemplate() {
    return new RestTemplate();
}

5.2.2 负载均衡策略

策略Bean 名行为
轮询(默认)RoundRobinLoadBalancer依次选择
随机自定义 ReactorLoadBalancer随机实例
同 zone 优先配置 spring.cloud.loadbalancer.zone减少跨机房延迟

自定义轮询 + 权重(Nacos 元数据 weight)需扩展 ServiceInstanceListSupplier(进阶选修)。

5.2.3 实例缓存

spring:
  cloud:
    loadbalancer:
      cache:
        enabled: true
        ttl: 35s

缓存减少对 Nacos 的压力;实例上下线可能有短暂延迟,可配合 shorter TTL。


5.3 Resilience4j 简介

Resilience4j 是轻量级容错库,Spring Cloud Circuit Breaker 抽象默认推荐实现之一。

模块作用
circuitbreaker熔断
retry重试(与 ch04 Feign Retry 二选一或组合谨慎)
ratelimiter限速
bulkhead舱壁隔离并发
timelimiter超时
调用 product-svc
    │
    ▼
CircuitBreaker(统计失败率)
    │  closed:正常
    │  open:直接 fallback
    │  half-open:放行少量探测
    ▼
Feign HTTP

5.4 依赖与配置

5.4.1 order-svc 依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>

5.4.1b gateway-svc 依赖(Gateway 熔断必加)

Gateway 基于 WebFlux,须使用 Reactor 版熔断器,不能只依赖 Servlet 栈的 spring-cloud-starter-circuitbreaker-resilience4j

<!-- gateway-svc/pom.xml -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency>

5.4.2 application 配置

resilience4j:
  circuitbreaker:
    instances:
      product-svc:                  # 实例名须与 Feign 熔断名一致(见 5.5.1 命名解析器)
        slidingWindowSize: 20
        minimumNumberOfCalls: 10
        failureRateThreshold: 50
        waitDurationInOpenState: 30s
        permittedNumberOfCallsInHalfOpenState: 5
        automaticTransitionFromOpenToHalfOpenEnabled: true
  timelimiter:
    instances:
      product-svc:
        timeoutDuration: 5s

spring:
  cloud:
    openfeign:
      circuitbreaker:
        enabled: true
参数含义
slidingWindowSize统计窗口调用次数
failureRateThreshold失败率达 50% 打开熔断
waitDurationInOpenState开路 30s 后转半开

5.5 Feign + CircuitBreaker 集成

5.5.1 启用与熔断实例命名

spring:
  cloud:
    openfeign:
      circuitbreaker:
        enabled: true

Feign 调用触发熔断时,Resilience4j 实例名默认Client名#方法签名(如 product-svc#getById(Long)),逐个方法配置实例不现实。注册 CircuitBreakerNameResolver(Spring Cloud OpenFeign 3.1+)统一改为按 Client 名共享一个熔断实例,与 5.4.2 的 product-svc 配置对应:

@Configuration
public class FeignCircuitBreakerConfig {

    @Bean
    public CircuitBreakerNameResolver circuitBreakerNameResolver() {
        // 熔断/限流实例名 = Feign Client 名,该 Client 的所有方法共用一个熔断器
        return (feignClientName, target, method) -> feignClientName;
    }
}
注意spring.cloud.openfeign.client.config.*没有 circuitBreakerName 这个配置项,网上部分教程的写法不会生效。命名只能由 CircuitBreakerNameResolver 控制。

Feign Client:

@FeignClient(
    name = "product-svc",
    path = "/api/v1/products",
    fallbackFactory = ProductClientFallbackFactory.class
)
public interface ProductClient {

    @GetMapping("/{id}")
    Result<ProductDto> getById(@PathVariable("id") Long id);
}

5.5.2 FallbackFactory

@Component
@Slf4j
public class ProductClientFallbackFactory implements FallbackFactory<ProductClient> {

    @Override
    public ProductClient create(Throwable cause) {
        return new ProductClient() {
            @Override
            public Result<ProductDto> getById(Long id) {
                log.warn("ProductClient fallback id={} reason={}", id, cause.toString());
                return Result.fail(ErrorCode.PRODUCT_SERVICE_DEGRADED);
            }

            @Override
            public Result<PageResult<ProductDto>> list(int page, int size) {
                return Result.fail(ErrorCode.PRODUCT_SERVICE_DEGRADED);
            }
        };
    }
}

降级策略

场景fallback 行为
商品详情返回「服务繁忙,请稍后」
列表页返回缓存快照(spring-boot-web ch10 Redis,选修)
下单关键路径明确失败,禁止静默成功

以下内容需解锁后阅读

试读已结束。解锁本章 ¥5.00,或开通年度会员畅读全部教程。
年度会员 ¥199.00/年; 小紫 AI 工作台有效会员 ¥99.00/年

正文仅在服务端鉴权后下发,未付费无法获取下半部分内容。