高并发系统的稳定性,不取决于单个组件多强,而取决于“保护策略是否成体系”。
很多团队有了限流,却没有熔断;有了熔断,却没有降级;最后线上仍然出现级联故障。
本文聚焦三件事:什么时候限流、什么时候熔断、什么时候降级。
【场景:下游抖动引发全链路超时】
常见故障链路:
- 下游服务 RT 变高。
- 上游线程池被阻塞。
- 重试放大流量,连接池耗尽。
- 核心接口被拖垮。
这类问题的本质是“没有在边界处阻断故障传播”。
【策略1:限流(控制入口流量)】
限流用于“系统还活着,但流量超出处理能力”。
常见算法:
- 固定窗口:实现简单,但边界抖动明显
- 滑动窗口:更平滑
- 令牌桶:支持突发流量,工程上最常见
if (!tokenBucket.tryAcquire()) {
return ApiResponse.fail("请求过多,请稍后重试");
}
实践建议:
- 按接口分级限流(核心接口优先)
- 按租户/用户限流,避免单点挤占
- 为限流拒绝打独立指标
【策略2:熔断(隔离不稳定依赖)】
熔断用于“下游已经不稳定,继续调用只会扩大损失”。
状态机:
- Closed:正常放行
- Open:快速失败
- Half-Open:小流量探测恢复
if (breaker.isOpen("payment-service")) {
return fallback("支付服务繁忙,请稍后重试");
}
try {
return paymentClient.pay(req);
} catch (Exception ex) {
breaker.recordFailure("payment-service");
throw ex;
}
实践建议:
- 熔断粒度按“依赖服务 + 接口”划分
- 熔断阈值按错误率和慢调用率双维度设置
- 半开探测流量要严格受控
【策略3:降级(保证核心功能可用)】
降级用于“资源不足时优先保核心路径”。
示例:
- 推荐/评论可降级
- 下单/支付不可降级
if (systemLoad.high()) {
return ApiResponse.ok("降级返回", cachedSummaryData);
}
实践建议:
- 先定义业务优先级(核心、重要、可延后)
- 每个服务要有明确降级开关
- 降级结果要可观测,不可“静默失败”
【组合策略:先限流,再熔断,最后降级】
可复用链路:
public Result handle(Request req) {
if (!rateLimiter.allow(req.api(), req.userId())) return rejected();
if (breaker.isOpen(req.dependency())) return degraded();
try {
return invokeDownstream(req);
} catch (Exception e) {
breaker.recordFailure(req.dependency());
return degraded();
}
}
这套顺序的目标是:
- 限流挡住外部压力
- 熔断隔离内部故障
- 降级保证核心可用
【稳定性治理检查清单】
- 入口是否有分级限流?
- 关键依赖是否配置熔断与半开探测?
- 是否定义了业务降级优先级?
- 降级是否有明确返回策略?
- 是否有拒绝率、熔断率、降级率监控?
- 是否做过压测和故障演练?
下期预告:
《Kafka vs RabbitMQ:消息队列选型的决策框架》