
【架构实战】限流熔断高并发系统的自我保护机制一、背景放量不放闸系统被冲垮2021年618大促营销团队搞了个秒杀活动。活动开始10秒流量直接是平时的100倍。我们的系统没有任何限流保护。结果数据库连接池瞬间耗尽默认200个连接涌入2000个并发请求订单服务的线程池全部阻塞Tomcat请求队列溢出Redis Cluster的某热Key把单节点CPU打到100%最糟糕的是库存服务的慢响应拖垮了上游的订单服务订单服务又拖垮了网关——雪崩了整个系统瘫痪了40分钟所有服务全部不可用包括和秒杀毫无关系的用户登录、商品浏览。运维总监后来复盘说了一句经典的话“宁可让一部分用户骂我们限流不让他们买也不能让所有用户都用不了。”限流熔断不是性能优化是系统自保。它的目标不是让更多人用而是让能用的部分不出事。二、限流控制入口流量2.1 限流算法对比算法原理优点缺点适用场景固定窗口每秒计数器清零实现简单临界突刺问题简单场景滑动窗口滑动时间窗口计数平滑内存开销稍大通用限流漏桶固定速率处理请求流量整形无法应对突发保护下游令牌桶固定速率放令牌允许突发实现稍复杂允许突发的场景2.2 Sentinel 限流实战// 1. 定义限流规则PostConstructpublicvoidinitFlowRules(){ListFlowRulerulesnewArrayList();// QPS限流每秒最多100个请求FlowRuleqpsRulenewFlowRule();qpsRule.setResource(createOrder);qpsRule.setGrade(RuleConstant.FLOW_GRADE_QPS);qpsRule.setCount(100);rules.add(qpsRule);// 并发线程数限流同时最多20个线程处理FlowRulethreadRulenewFlowRule();threadRule.setResource(calculateDiscount);threadRule.setGrade(RuleConstant.FLOW_GRADE_THREAD);threadRule.setCount(20);rules.add(threadRule);FlowRuleManager.loadRules(rules);}// 2. 使用注解限流ServicepublicclassOrderService{SentinelResource(valuecreateOrder,blockHandlercreateOrderBlockHandler)publicOrdercreateOrder(OrderRequestrequest){// 业务逻辑returnorderDao.insert(request);}// 限流后的处理逻辑publicOrdercreateOrderBlockHandler(OrderRequestrequest,BlockExceptionex){log.warn(订单创建被限流: userId{},request.getUserId());thrownewBizException(429,系统繁忙请稍后再试);}}2.3 多层限流架构┌──────────────────────────────────────────────┐ │ 多层限流防护体系 │ │ │ │ Layer 1: Nginx 接入层限流 │ │ limit_req_zone $binary_remote_addr │ │ zoneperip:10m rate10r/s; │ │ → 拦截恶意IP防止单IP打爆 │ │ │ │ Layer 2: API网关限流Sentinel/Kong │ │ /api/order/* → QPS10000 │ │ /api/admin/* → QPS100 │ │ → 按API路径限流保护敏感接口 │ │ │ │ Layer 3: 应用层限流Sentinel │ │ createOrder资源 → QPS5000 │ │ → 按业务资源限流精准控制 │ │ │ │ Layer 4: 数据库层限流 │ │ DB连接池 maxActive200 │ │ → 保护数据库不被冲垮 │ └──────────────────────────────────────────────┘三、熔断阻止故障扩散3.1 熔断器状态机┌────────────┐ │ CLOSED │ ← 正常状态请求直接通过 │ (断路器关闭) │ └─────┬──────┘ │ 错误率超过阈值(如50%) │ 或慢调用比例超过阈值 ▼ ┌────────────┐ │ OPEN │ ← 熔断状态请求直接拒绝 │ (断路器打开) │ └─────┬──────┘ │ 等待熔断时长(如10秒) ▼ ┌────────────┐ │ HALF_OPEN │ ← 半开状态放少量请求试探 │(断路器半开) │ └─────┬──────┘ │ ┌─────┴─────┐ │ │ ▼ ▼ 试探成功 试探失败 → CLOSED → OPEN3.2 Sentinel 熔断实战PostConstructpublicvoidinitDegradeRules(){ListDegradeRulerulesnewArrayList();// 慢调用比例熔断DegradeRuleslowRulenewDegradeRule();slowRule.setResource(queryProduct);slowRule.setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType());slowRule.setCount(200);// 响应时间超过200ms即为慢调用slowRule.setSlowRatioThreshold(0.5);// 慢调用比例超过50%触发熔断slowRule.setMinRequestAmount(10);// 最小请求数统计窗口内slowRule.setStatIntervalMs(10000);// 统计窗口10秒slowRule.setTimeWindow(10);// 熔断时长10秒rules.add(slowRule);// 异常比例熔断DegradeRuleerrorRulenewDegradeRule();errorRule.setResource(createOrder);errorRule.setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType());errorRule.setCount(0.3);// 异常比例超过30%触发熔断errorRule.setMinRequestAmount(20);errorRule.setStatIntervalMs(10000);errorRule.setTimeWindow(15);rules.add(errorRule);DegradeRuleManager.loadRules(rules);}// 熔断降级处理SentinelResource(valuequeryProduct,fallbackqueryProductFallback)publicProductqueryProduct(LongproductId){returnproductDao.findById(productId);}// 降级逻辑返回缓存数据或默认数据publicProductqueryProductFallback(LongproductId,Throwablet){log.error(查询商品降级: productId{},productId,t);// 从本地缓存获取兜底数据ProductcachedlocalCache.get(productId);if(cached!null){returncached;}// 返回默认商品信息returnProduct.builder().id(productId).name(商品信息加载中...).price(newBigDecimal(0.00)).build();}3.3 降级策略分级Level 0: 无降级正常 → 所有功能正常 Level 1: 非核心降级系统负载 80% → 关闭推荐算法用静态推荐替代 → 关闭实时数据统计延迟到低峰期计算 → 关闭用户行为日志采集 Level 2: 部分核心降级系统负载 90% → 关闭优惠券计算不享受优惠但能下单 → 关闭积分累加延迟累加 → 关闭短信通知改用App推送 Level 3: 全面降级系统濒临崩溃 → 只保留核心下单链路 → 静态页面替代动态页面 → 排队机制替代直接访问四、限流熔断最佳实践4.1 限流阈值设定不要拍脑袋设阈值要基于压测数据。正确的阈值设定流程 1. 全链路压测 → 找到服务极限QPS如: 50000 2. 取极限QPS的70%作为限流阈值如: 35000 原因留30%余量应对突发流量 3. 线上观察1周 → 根据实际CPU/内存/错误率微调 4. 大促期间 → 临时放宽到80%如: 400004.2 限流效果监控// 通过Sentinel Dashboard实时监控// 关键指标// - 通过的QPS// - 被拦截的QPS限流拒绝数// - 平均响应时间// - 熔断状态// Prometheus告警规则groups:-name:sentinel_alerts rules:-alert:SentinelBlockHighexpr:rate(sentinel_block_total[1m])100for:2m labels:severity:warning annotations:summary:限流拦截量过高-alert:CircuitBreakerOpenexpr:sentinel_circuit_breaker_state1for:1m labels:severity:critical annotations:summary:熔断器已打开4.3 常见坑点坑1限流后返回500错误码限流是预期行为应该返回429Too Many Requests前端统一处理稍后再试的提示。坑2只限流量不限并发QPS限了100但如果每个请求耗时10秒实际上是1000个线程在跑。必须配合并发数限流。坑3熔断和限流阈值设一样熔断和限流的语义不同限流 主动保护我知道我的上限主动拒绝多余请求熔断 被动保护下游出问题了我只能熔断保护自己五、总结限流 vs 熔断 vs 降级的关系机制目标触发条件表现限流控制请求量超过预设QPS/并发拒绝多余请求熔断阻止故障扩散下游错误率高快速失败降级保证核心链路系统负载高关闭非核心功能三者配合使用限流是第一道防线熔断是第二道防线降级是最后兜底。核心经验限流阈值要留余量取极限QPS的70%作为阈值不要顶格设置熔断要快恢复要慢5秒内发现故障15秒后再试探恢复降级要有预案提前设计好几套降级方案别等出问题再想限流信息要透传429错误码要一路传到前端别吞掉监控比规则更重要没监控限流熔断了你都不知道限流熔断是系统的免疫系统——没有它一个服务挂了会拖死整个集群。有它最多只是部分用户慢一点不会全面崩溃。个人观点仅供参考