连载中 10/20

熔断器:三态模型的断路哲学

2026-07-11 · 1186 阅读 · 0 评论 · 0 赞

另一半问题:出去的调用

限流篇解决的是「进来的流量」怎么少接点。但第 1 篇雪崩链里还有另一半:会员服务调用订单服务,订单病了(RT 5 秒),会员的线程一个个阻塞在等待上——上游不是被流量打死的,是被自己「礼貌的等待」拖死的。此时重试是叩得更响,扩容是给病人搬椅子,都不对症。对症的机制是熔断器(Circuit Breaker):发现下游病了,就停止叩门,请求直接快速失败——家里的空气开关早就想明白了这件事,电流异常直接跳闸,断电保电路。

三个状态,一台断路器

熔断器的全部智慧浓缩在三个状态里:

            错误率/慢调用超阈值
  ┌──────────────────────────────┐
  │                              ▼
[CLOSED 关闭]                [OPEN 打开]
  ▲                            │
  │ 探测成功                    │ 休眠时间到
  │                            ▼
  └──────[HALF-OPEN 半开] ◄────┘
        探测失败 ──────► 回到 OPEN

CLOSED(闭合):正常态,请求全部通过,同时持续统计下游的错误率与慢调用比例——断路器在闭合时也睁着眼。OPEN(打开):统计指标越过阈值,断路器跳闸,之后所有请求立即失败(走降级逻辑),不再发出网络调用——上游线程瞬间解脱,下游获得喘息。HALF-OPEN(半开):跳闸持续一段「休眠时间」后进入试探态,放行少量探测请求;探测成功说明下游恢复,断路器闭合回 CLOSED,全线恢复;探测失败则重新跳闸回 OPEN,继续休眠。

手写一个迷你熔断器

状态机不复杂,核心代码几十行,自己写一个便于理解骨架:

public class MiniBreaker {
    enum State { CLOSED, OPEN, HALF_OPEN }
    private volatile State state = State.CLOSED;
    private final AtomicInteger failures = new AtomicInteger();
    private volatile long openedAt = 0;
    private static final int THRESHOLD = 50;      // 失败 50 次跳闸
    private static final long SLEEP_MS = 10_000;  // 休眠 10 秒

    public boolean allow() {
        if (state == State.OPEN) {
            if (System.currentTimeMillis() - openedAt > SLEEP_MS) {
                state = State.HALF_OPEN;          // 休眠到期,进入试探
                return true;
            }
            return false;                          // 熔断中,快速失败
        }
        return true;
    }
    public void record(boolean success) {
        if (success) { failures.set(0); state = State.CLOSED; }
        else if (failures.incrementAndGet() >= THRESHOLD) {
            state = State.OPEN;                    // 连续失败,跳闸
            openedAt = System.currentTimeMillis();
        }
    }
}

真实生产不会用这么简的版本(缺滑动统计窗口、最小请求数、并发控制),下一版框架轮到 Sentinel 与 Resilience4j,但状态机的骨架就是这个三态,框架只是把「怎么判定病了」做得更科学。

熔断保护的是谁

一个常被问反的问题:熔断是保护上游还是下游?答案是都保护,但先保护上游。对上游:跳闸后请求不再发出,线程不再阻塞,上游自己的资源(线程池、连接)不再被拖垮——这是第 1 篇连坐链的直接解药。对下游:叩门声停了,故障中的下游获得喘息空间去恢复(GC 能跑完、连接池能清空、磁盘 IO 能跟上),而不是在愈来愈多的请求里窒息到底。熔断的休眠时间就是下游的 ICU 时间。

与限流、重试的分工

机制管什么动作触发依据
限流进来的流量主动拒绝超额预设阈值(静态)
熔断出去的调用停止调用下游实时健康指标(动态)
重试瞬时失败再试一次可重试的错误类型

三者各司其职且互相配合:重试要尊重熔断状态(Open 时不重试),限流的触发率与熔断的跳闸事件都要进监控。熔断器「怎么判定病了」有一整门学问——错误率、慢调用比例、统计窗口、最小请求数,下一篇把判定标准拆开细讲。

503

10 年全栈工程师 · 503咖啡馆主理人

#熔断器#三态模型#断路器#快速失败#Half-Open#状态机

评论 (0)

相关推荐

连载中 12/20

排查四件套:jstack、jmap、jstat、jcmd 的实战分工

jstack 看线程在干什么,jmap 看堆里装了什么,jstat 看运行时在变什么,jcmd 是统一入口。四把刀各管一段,配合着用没有查不动的现场。

#jstack#jmap#jstat#jcmd#排查工具
2026-09-16 · 5 阅读 · 0 评论 · 0 赞
连载中 11/20

GC 日志:把回收过程翻译成人话

一行 GC 日志里塞着七种信息:谁触发的、收了哪、停了多久、活了哪些。加上 -Xlog 配置,再加上日志分析工具,GC 不再是只能盯监控曲线的黑盒。

#GC日志#Xlog#日志分析#GC监控#Full GC排查
2026-09-16 · 13 阅读 · 0 评论 · 0 赞
连载中 10/20

ZGC:亚毫秒停顿是怎么炼成的

百 G 大堆停顿不到一毫秒,靠的是把搬家全部挪到并发阶段——着色指针让引用自带状态,读屏障让搬运中的对象依然可访问。代价是吞吐与内存,收益是停顿与堆大小解耦。

#ZGC#着色指针#读屏障#亚毫秒停顿#分代ZGC
2026-09-15 · 8 阅读 · 0 评论 · 0 赞