1.1 限流
限流的令牌桶/漏桶/滑动窗口等算法详见 分布式系统理论基础 的”流量控制”章节。
在微服务架构中,限流的落点通常在三层:
- 网关层:全局限流,防止流量打死任何下游
- RPC 框架层:Dubbo/Sentinel 拦截器,服务级限流
- 业务层:对特定接口/资源(如秒杀 SKU)的精准限流
1 2 3 4 5 6 7 8 9 10
| @SentinelResource(value = "createOrder", blockHandler = "createOrderFallback") public Order createOrder(CreateOrderRequest request) { }
public Order createOrderFallback(CreateOrderRequest request, BlockException e) { return Order.fail("系统繁忙,请稍后再试"); }
|
1.2 熔断(Circuit Breaker)
熔断器的灵感来自电路保险丝:当电流过大时自动断开,保护电路。在微服务中同理——当某个下游服务故障率达到阈值,熔断器断开,后续请求直接失败(快速失败),不继续压垮它。
Hystrix 断路器状态机:
1 2 3 4 5 6 7 8 9 10 11 12 13
| 请求失败数超过阈值 ┌─────────┐ ──────────────────────► ┌─────────┐ │ CLOSED │ │ OPEN │ │ (闭合) │ ◄─────────────────────── │ (断开) │ │ │ 超时后恢复检测 │ │ └─────────┘ └─────────┘ ▲ │ │ │ 探测请求成功 │ ┌─────────────┐ │ └─────────│ HALF-OPEN │◄───────────┘ │ (半开) │ └─────────────┘ 探测请求失败 → 重新 OPEN
|
核心参数:
1 2 3 4 5
| HystrixCommand.Setter .withCircuitBreakerEnabled(true) .withCircuitBreakerRequestVolumeThreshold(20) .withCircuitBreakerErrorThresholdPercentage(50) .withCircuitBreakerSleepWindowInMilliseconds(5000);
|
注意事项:
- 熔断器不是越多越好——每个熔断器维护独立的状态和线程池,开销不可忽视
- 不要对所有异常都触发熔断计数——业务异常(如”商品已下架”)不是下游故障,不应参与熔断统计
- 熔断颗粒度:一般以服务为单位,细粒度的可以到方法级别
1.3 降级(Fallback)
降级是熔断/限流被触发后的兜底逻辑。当系统判定当前不可靠时,宁可返回一个降级结果,也不让上游超时等待。
分类:
| 类型 |
说明 |
示例 |
| 容错降级 |
被熔断/限流时触发 |
返回缓存数据 / 提示”请重试” |
| 优雅降级 |
主动关闭非核心功能,保证核心可用 |
双11时关闭评论、推荐 |
| 异步降级 |
同步调用失败转为异步补偿 |
打款失败 → 记录 → T+1 重试 |
1 2 3 4 5 6 7 8 9 10
| @HystrixCommand(fallbackMethod = "getUserFallback") public User getUser(Long id) { return userService.getUser(id); }
public User getUserFallback(Long id) { return cacheService.getUserFromCache(id); }
|
1.4 Sentinel
Sentinel(阿里开源)是取代 Hystrix 的更好选择,Hystrix 已进入维护模式。Sentinel 的核心能力:
| 能力 |
说明 |
| 流控 |
QPS/并发线程数/匀速排队(漏桶效果) |
| 熔断降级 |
慢调用比例/异常比例/异常数 |
| 热点参数限流 |
对特定参数值(如 SKU ID)单独限流 |
| 系统保护 |
系统 Load/CPU/RT 超过阈值时自动限流 |
| 规则持久化 |
推送规则到 Nacos/Apollo,动态生效 |
| 控制台 |
可视化 Dashboard,实时监控秒级数据 |
Sentinel vs Hystrix:
| 维度 |
Hystrix |
Sentinel |
| 隔离策略 |
线程池/信号量 |
信号量(轻量) |
| 熔断粒度 |
服务级 |
接口/方法/参数级 |
| 规则配置 |
代码硬编码 |
控制台动态下发 |
| 实时监控 |
Hystrix Dashboard |
Sentinel Dashboard |
| 自适应 |
无 |
系统自适应保护 |
| 维护状态 |
停更 |
活跃 |
1 2 3 4 5 6 7 8
| FlowRule rule = new FlowRule(); rule.setResource("createOrder"); rule.setGrade(RuleConstant.FLOW_GRADE_QPS); rule.setCount(100); rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP); rule.setWarmUpPeriodSec(10); FlowRuleManager.loadRules(Collections.singletonList(rule));
|
最佳实践:规则统一在 Sentinel Dashboard 管理,通过 Nacos 做规则持久化,确保 Dashboard 重启后规则不丢失。
1 2 3 4 5 6 7 8 9 10 11 12 13
| spring: cloud: sentinel: transport: dashboard: 127.0.0.1:8080 datasource: ds1: nacos: server-addr: 127.0.0.1:8848 data-id: ${spring.application.name}-sentinel-rules group-id: DEFAULT_GROUP data-type: json rule-type: flow
|
1.5 隔离
隔离是防止”服务内一个接口的异常拖整个服务”的关键。
线程池隔离:
- 每个依赖服务分配独立的线程池
- 优点:完全隔离,下游慢不会耗尽上游的线程
- 缺点:线程上下文切换开销大,OOM 风险(线程栈内存)
信号量隔离:
- 限制并发数,使用调用线程执行
- 优点:轻量,无线程切换开销
- 缺点:不隔离超时——下游慢会阻塞调用线程
1 2 3 4 5 6 7 8 9 10 11 12 13
| 线程池隔离(Hystrix): 信号量隔离(Sentinel):
┌──────────────┐ ┌──────────────┐ │ 调用线程 │ │ 调用线程 │ │ ▼ │ │ ▼ │ │ HystrixCmd │ │ Sentinel │ │ ▼ │ │ 检查信号量 │ │ ┌───────────┐ │ │ ▼ │ │ │ 线程池 (10) │ │ │ 直接执行调用 │ │ │ ▼ │ │ │ (若超过阈值则 │ │ │ 下游服务 │ │ │ 直接Block) │ │ └───────────┘ │ └──────────────┘ └──────────────┘
|
生产建议:
- 大多数场景用信号量隔离(Sentinel 默认),性能更好
- 当依赖的服务经常有慢查询且不可控时,用线程池隔离——宁可开销大一点,不能让整个服务阻塞