熔断、降级与限流

微服务稳定性保障三大手段:熔断器原理、降级策略、限流算法(令牌桶/漏桶/滑动窗口)及舱壁隔离模式。

熔断、降级与限流

微服务调用链中,单点故障可能引发级联雪崩。熔断、降级、限流是保障系统稳定性的三道防线。

1. 熔断器(Circuit Breaker)

状态机

        ┌─────────┐ 失败率>阈值    ┌─────────┐
        │  CLOSED │──────────────→│  OPEN   │
        │ (正常)   │               │ (熔断)   │
        └────┬────┘               └────┬────┘
             │                         │
      失败计数恢复                      │ 超时后
             │                         ↓
             │                  ┌─────────────┐
             └─────────────────│ HALF-OPEN   │
                探测失败        │ (半开/探测) │
                               └─────────────┘

参数配置

参数说明典型值
failureThreshold触发熔断的失败次数/比例5 次或 50%
slowCallThreshold触发熔断的慢调用比例80%
waitDurationInOpenStateOPEN 持续时间30s
permittedNumberOfCallsInHalfOpenState半开探测次数3

Resilience4j 示例

CircuitBreakerConfig config = CircuitBreakerConfig.custom()
    .failureRateThreshold(50)
    .waitDurationInOpenState(Duration.ofSeconds(30))
    .permittedNumberOfCallsInHalfOpenState(3)
    .slidingWindowSize(100)
    .build();

CircuitBreaker cb = CircuitBreaker.of("orderService", config);

// 装饰调用
Supplier<String> decorated = CircuitBreaker
    .decorateSupplier(cb, () -> orderClient.getOrder(id));
String result = Try.ofSupplier(decorated)
    .recover(throwable -> "fallback_order")
    .get();

2. 降级(Degrade)

当服务不可用或响应过慢时,提供简化替代方案。

降级策略

策略场景示例
返回默认值非核心数据推荐列表为空时返回热门商品
返回缓存读服务从 Redis 读取历史数据
功能裁剪核心功能优先关闭评论功能,保留购买
同步转异步非实时要求订单创建后异步发送通知

Sentinel 降级

// 基于慢调用比例的降级
DegradeRule rule = new DegradeRule("getOrder")
    .setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO)
    .setCount(0.5)           // 慢调用比例阈值
    .setTimeWindow(30)       // 熔断时长(秒)
    .setSlowRatioThreshold(500); // 慢调用阈值(ms)

3. 限流(Rate Limiting)

控制请求速率,防止服务被突发流量击垮。

算法对比

【令牌桶】              【漏桶】                【滑动窗口】
  ┌─────┐              ┌─────┐
  │令牌 │ ← 匀速产生    │请求 │ → 匀速漏出
  └─┬───┘              └──┬──┘
    │ 取令牌              │ 排队
    ▼                    ▼
  服务                  服务
  
  允许突发              平滑流量              精确计数
算法特点适用场景
令牌桶允许突发,平均速率可控大多数限流场景
漏桶强制平滑,无突发需要严格平滑的下游
滑动窗口精确统计窗口内请求短时限流
固定窗口实现简单,存在临界突刺统计精度要求低

Guava RateLimiter

RateLimiter limiter = RateLimiter.create(100); // QPS = 100

// 阻塞获取
limiter.acquire();

// 非阻塞尝试
if (limiter.tryAcquire(10, TimeUnit.MILLISECONDS)) {
    process(request);
} else {
    return "Too Many Requests";
}

分布式限流(Redis + Lua)

-- 滑动窗口限流
local key = KEYS[1]
local now = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local limit = tonumber(ARGV[3])

redis.call('ZREMRANGEBYSCORE', key, 0, now - window)
local count = redis.call('ZCARD', key)

if count < limit then
    redis.call('ZADD', key, now, now)
    redis.call('EXPIRE', key, window)
    return 1  -- 允许
else
    return 0  -- 拒绝
end

4. 舱壁隔离(Bulkhead)

将服务资源划分为独立池,一个池的故障不影响其他池。

无隔离:                          舱壁隔离:
                    
   ┌─────┐         ┌──────┐         ┌──────┐
   │所有请求│         │查询请求│         │写请求│
   └──┬──┘         └───┬──┘         └───┬──┘
      │ 共享线程池        │ 线程池 A       │ 线程池 B
      ▼                ▼                ▼
   ┌─────┐         ┌─────┐         ┌─────┐
   │DB连接│         │DB连接│         │DB连接│
   └─────┘         └─────┘         └─────┘

Resilience4j Bulkhead

ThreadPoolBulkheadConfig config = ThreadPoolBulkheadConfig.custom()
    .maxThreadPoolSize(10)
    .coreThreadPoolSize(5)
    .queueCapacity(20)
    .build();

ThreadPoolBulkhead bulkhead = ThreadPoolBulkhead.of("backendA", config);
CompletionStage<String> result = bulkhead.executeSupplier(() -> backendService.call());

5. 组合使用

          请求入站
             ↓
    ┌─────────────────┐
    │  限流(全局/用户)│ ← 第一层:防过载
    └─────────────────┘
             ↓
    ┌─────────────────┐
    │   舱壁隔离       │ ← 第二层:资源隔离
    └─────────────────┘
             ↓
    ┌─────────────────┐
    │   熔断器         │ ← 第三层:故障隔离
    └─────────────────┘
             ↓
    ┌─────────────────┐
    │   降级预案       │ ← 最后防线
    └─────────────────┘

6. 实战:Spring Cloud + Sentinel

spring:
  cloud:
    sentinel:
      transport:
        dashboard: sentinel-dashboard:8080
      datasource:
        flow:
          nacos:
            server-addr: nacos:8848
            dataId: ${spring.application.name}-flow-rules
            rule-type: flow
@RestController
public class OrderController {
    @GetMapping("/orders/{id}")
    @SentinelResource(
        value = "getOrderById",
        blockHandler = "handleBlock",
        fallback = "handleFallback"
    )
    public Order getOrder(@PathVariable Long id) {
        return orderService.getById(id);
    }
    
    public Order handleBlock(Long id, BlockException ex) {
        throw new TooManyRequestsException();
    }
    
    public Order handleFallback(Long id, Throwable ex) {
        return Order.empty(); // 降级
    }
}

总结

手段目标触发条件
限流防止过载请求速率超过阈值
熔断防止故障扩散错误率/慢调用超标
降级有损服务依赖服务异常
隔离资源保护资源竞争

四者配合使用,构建多层防护体系,是微服务高可用的基石。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「架构」更多文章

  1. 架构评审与技术债管理
  2. SLA/SLO/SLI 与容量规划
  3. 云原生架构模式