生产环境应使用sony/gobreaker而非hystrix-go或自研方案;它被go-zero、kratos等主流框架验证,单文件无依赖、状态语义清晰、支持滑动窗口与半开探测,而hystrix-go因重模型与go特性冲突易误判,自研则难以保障并发安全与状态边界。

直接用 sony/gobreaker,别自己手写或选 hystrix-go
生产环境该用哪个熔断库,结论很明确:用 sony/gobreaker。它被 go-zero、kratos 等主流框架大量验证过,单文件、无外部依赖、状态机语义清晰,滑动窗口和半开探测逻辑稳定。而 hystrix-go 是 Java Hystrix 的移植,保留了线程池隔离、命令包装等重模型,在 Go 的 goroutine 场景下反而容易误判——比如 MaxConcurrentRequests 会和 HTTP 连接池冲突,导致请求卡在“等待执行”而非真实失败;它的 SleepWindow 是固定休眠,不感知下游是否已恢复。
自研熔断器也极不推荐:并发安全、滑动窗口统计、状态转换边界(尤其是半开到关闭的判定条件)、时钟漂移处理,任何一个点没压测过都可能在线上引发雪崩。
每个下游服务必须配独立 CircuitBreaker 实例
熔断器不是全局开关,而是每个依赖服务专属的“保险丝”。共用一个实例会导致 A 服务故障把 B 服务也拖垮。实际配置时:
-
http.Client调用支付服务,就建一个Name: "payment-service-call"的gobreaker.CircuitBreaker -
grpc.ClientConn连用户中心,就另建一个Name: "user-service-grpc" - 数据库连接池(如
sql.DB)也应单独配,命名如"order-db-query"
参数建议:MaxRequests ≥ 10(设成 1 容易因单次网络抖动误熔断),Timeout = 15s(这是熔断后多久尝试半开,不是调用超时),Interval 设为 30s~2m(太短如 5s 会把瞬时抖动当持续故障)。
Execute 只包真正发起请求的那一行
cb.Execute 的作用范围必须精准——只包裹实际发请求的动作,比如 client.Do(req) 或 stub.GetUser(ctx, req),而不是整个 handler 或 client 初始化逻辑。
常见错误包括:
- 把
*http.Client或*grpc.ClientConn整个塞进Execute,导致连接复用失效、资源泄漏 - 在
Execute里做参数校验、日志记录、缓存查询,这些本不该受熔断状态影响 - 没主动将 5xx 响应转为
error,导致gobreaker无法统计失败次数
fallback 函数签名必须严格匹配主函数:func() (interface{}, error),且内部不能 panic、不能调外部服务、不能写 DB——它必须是纯内存计算,比如返回本地缓存值或静态默认结构体。
必须配合 context.WithTimeout 和 Prometheus 监控
熔断器本身不管超时,Timeout 字段是半开探测周期,不是请求超时。所有外部调用必须显式套 context.WithTimeout,否则 fallback 也可能卡死。
没监控的熔断等于黑盒拉闸。必须暴露 gobreaker.Metrics 到 Prometheus,重点盯三个指标:
-
circuit_breaker_state(当前状态,0=closed, 1=open, 2=half-open) -
circuit_breaker_requests_total(按状态分组的请求数) -
circuit_breaker_fallback_total(降级触发次数)
最容易被忽略的是:熔断状态变更后,要立刻检查下游服务的真实可用性——比如 StateOpen 时,是否真的有网络中断或 503?还是只是 fallback 写错了返回了 error?这个因果链必须靠指标+日志交叉验证,不能只看熔断器状态。











