限流与熔断:系统的保险丝与断路器——Java 工兵连第 20 篇(第二季收官)
「Java 工兵连」第 20 篇,两季收官。选限流熔断压轴,因为它把这一季的最后一课补上了:前面讲的是让系统跑得快,这篇讲让系统死不了——而「死不了」,往往比「跑得快」更值钱。
先立分工,一字不差地记:
限流保自己(入口),熔断保队友(出口),降级是共同的预案。
一、先建直觉:景区与断路器
- 限流 = 景区每日承载量:超过上限就停止售票(拒绝)、门口排队(削峰)、改日再来(降级引导)——保护的是景区自己不被挤垮。流量是从外面来的,所以装在入口;
- 熔断 = 家里的断路器:某个电器短路(下游服务故障),断路器自动跳闸——牺牲这一路,保住整个房子(你的线程池不被拖死)。故障是从里面传导的,所以装在出口(调用下游的地方);
- 降级 = 停电预案:蜡烛、备用发电机——主路不通时走兜底逻辑。
二、限流四算法:一张图选型
固定窗口:每分钟一个计数桶,最简单。死穴是边界突刺——59 秒和 61 秒各放走 N 个,交界瞬间实际过了 2N。
滑动窗口:把一分钟切成 6 个 10 秒小格,窗口随时间滑动——边界消失、统计平滑。精确版记日志(耗内存),工程主流用滑动计数(Sentinel 的做法,内存换掉精度小误差)。
漏桶:请求进桶,恒定速率流出处理——绝对平滑,下游永远匀速。代价是容不了突发(脉冲流量全在排队),而且桶本身要设界——无界漏桶就是无界队列,这一季的「无界」暗线最后一班岗。
令牌桶:匀速往桶里发令牌(桶容量有限),请求拿到令牌才放行——平均速率受控,又允许突发(攒下的令牌一次用光)。Guava RateLimiter、Sentinel 默认流派。
选型一句话:要平滑用漏桶,要突发用令牌——互联网业务大多珍惜突发能力,令牌桶是主流。三个配套维度别漏:层级(网关 → 应用 → 线程池/连接池——第 1 篇的线程池本质就是并发上限的限流器)、对象(全局 / 接口 / 单用户——防刷必备)、动作(拒绝 429、排队 MQ 削峰、降级兜底)。
三、熔断三态机:跳闸与试送电
熔断器是个状态机,三个状态画成环(hero 图右上):
- 关闭(Closed):正常放行,持续统计滑动窗口内的失败率 / 慢调用比例;
- 打开(Open):统计值越过阈值 → 快速失败(直接抛异常/走降级,不再发起对下游的调用)——这一跳是「断尾」:下游已经趴了,每一次真实调用都在消耗自己的线程和连接;
- 半开(Half-Open):冷却期(比如 30 秒)过后放行少量探测请求——成功则回关闭(恢复),失败则回打开(继续跳闸)。像检修后的「合闸试送电」。
两个容易栽跟跤的参数细节:最小请求数——样本太少不判断(5 个请求错 3 个就熔断是误伤,宁可不判);熔断时长别太长——下游可能 10 秒就恢复了,你却熔 5 分钟,恢复速度也是可用性。
生态三选:Sentinel(阿里系,流控+熔断+系统自适应一体,控制台生态好)、Resilience4j(轻量函数式,Spring 官方生态位)、Hystrix(停止维护,只作为遗产认识)。新项目二选一,别犹豫。
四、级联雪崩:六道防线
把两季的珠子串成项链——一次真实的全站雪崩长这样:DB 变慢 → 上游调用堆积、线程池打满(第 1 篇)→ 超时后重试又把流量放大一倍(重试风暴)→ 更多服务的线程与连接耗尽 → 依赖它的服务接连倒下(第 16 篇雪崩的分布式版)。防线要纵深布防,一道都不多余:
- 超时——一切的前提。没有超时的重试只是延长痛苦;每个远程调用必须有界;
- 重试要克制——指数退避(backoff)+ 重试预算(retry budget,限制重试占比),幂等才可重试(第 18 篇 Kafka 的幂等课在这里再上一遍);
- 熔断——止损大闸,别让坏消息反复进城;
- 限流——入口闸门,洪峰来时先保住核心;
- 降级——被限被熔之后用户看什么:兜底数据(默认推荐、缓存的旧值——第 16 篇逻辑过期的旧值先顶正是降级)、简化逻辑、异步化提示「处理中」。预案必须演练过才算存在——大促前压测降级开关,就是消防演习;
- 隔离(舱壁模式)——线程池/信号量按业务分:评论服务挂了,最多淹掉「评论舱」,下单主流程不进水。第 1 篇「池按业务分」埋的种子,到这里开花。
老兵点评
- 稳定性方案的第一性问题:算清楚「死多少能接受」。限流阈值不是拍出来的:压测拿到系统容量 → 留 30% 余量 → 按核心/非核心分级配额。这和缓存篇「丢多少能接受」、Kafka 篇「重不重能接受」是同一把尺子——两季 20 篇,其实反复在教这一件事:把『多少』说出来,工程方案自动唯一。
- 最被低估的防线是第 1 道和第 6 道。超时和隔离不需要任何新组件,却在真实事故里救场最多——因为它们在「故障传导路径」上设卡,而不是在故障发生后补救。给每个远程调用写超时,比引入任何框架都重要。
- 面试段位差:初级背「令牌桶漏桶区别」;中级讲三态机与参数细节(最小请求数、半开探测);高级讲重试风暴与重试预算、舱壁隔离、以及「限流阈值由压测容量倒推」——聊到这层是在聊容量治理。
带走三句话
- 分工口诀:限流保自己(入口),熔断保队友(出口),降级是预案——漏桶匀速过,令牌容突发。
- 熔断三态:关 → 开(失败率超阈,快速失败)→ 半开(冷却后试送电);记得最小请求数,防小样本误伤。
- 六道防线纵深布防:超时、重试退避、熔断、限流、降级、隔离(舱壁)——预案演练过才算存在。
🎖️ 「Java 工兵连」第 20 篇 · 两季 20 篇至此完结。 → 上一篇:第 19 篇 · 分库分表与分布式 ID | 回到专栏目录 →。从线程池的四步走,到六道防线的纵深布防——一路那句暗线收口:把「多少」说出来,方案自动唯一。第三季见。
❦ 终 ❦