gobreaker.Execute仅包裹实际调用(如client.Do(req)),不包整个client;必须返回(interface{}, error),5xx等需主动转error;fallback仅在ErrOpen或panic时触发,须类型匹配且纯内存无副作用。

gobreaker.Execute 只包 Do,不包整个 client
熔断器不是加在 HTTP 客户端或 gRPC 连接池上,而是加在「发起调用」的那一行。常见错误是把 http.Client 或 grpc.ClientConn 整个传给 Execute,结果它根本没法统计失败——因为没执行请求。
-
Execute第一个参数必须是真正发请求的函数,比如client.Do(req)或stub.GetUser(ctx, req) - 返回值必须是
(interface{}, error):成功时返回结果(哪怕nil),失败时返回非nil错误 - HTTP 5xx、gRPC
codes.Unavailable、dial tcp: i/o timeout都要主动转成error,否则不计入失败计数 - 别在
Execute里做重试、log、metric 上报——这些会污染失败判定逻辑
fallback 函数必须手动触发,且类型严格匹配
gobreaker.Execute 的第三个参数(fallback)只在两种情况触发:熔断器处于 Open 状态(返回 gobreaker.ErrOpen),或主函数 panic。它不会捕获超时、503、context canceled 等常规错误。
- 正确流程是:
res, err := cb.Execute(...)→if errors.Is(err, gobreaker.ErrOpen)→ 手动调用你的降级函数 - 降级函数签名必须和主函数完全一致,例如主函数是
func() (*User, error),fallback 也得是这个类型 - fallback 内部禁止访问 DB、调其他服务、起 goroutine;推荐从
sync.Map或本地 LRU cache 读缓存,或用DefaultUser()构造静态响应 - 返回
&User{}是危险的——序列化后是{"name":"","age":0},前端可能当成真实空数据;应显式初始化字段
Timeout 和 Interval 不是超时时间,别设错
Timeout 是“熔断后多久尝试半开”,Interval 是“滑动窗口多长时间重置”,二者都跟单次调用超时无关。设错会导致恢复延迟或误判抖动。
-
Timeout建议设15 * time.Second:太短(如5s)会让半开探测过于激进;太长(如60s)下游已恢复,你还在休眠 -
Interval控制失败率统计周期,选30s ~ 2m;设成5s容易把一次网络抖动当持续故障 -
MaxRequests别设1:半开刚进就因单次失败又切回Open,实际建议 ≥10 - 单次调用超时必须用
context.WithTimeout单独控制,和熔断器解耦
没监控的熔断等于黑盒拉闸
熔断器本身不暴露状态,gobreaker.Metrics 必须接入 Prometheus,否则你无法知道它什么时候开了、为什么开、fallback 是否被频繁触发。
立即学习“go语言免费学习笔记(深入)”;
- 重点盯三个指标:
circuit_breaker_state(当前状态)、circuit_breaker_requests_total(按状态+结果打标)、circuit_breaker_fallback_total - 不要只看
ErrOpen次数,还要对比consecutive_failures和配置的阈值,确认是否真由错误率触发 - 如果
fallback_total持续上涨但state一直是Closed,说明降级逻辑被误用(比如在非ErrOpen场景下也调了 fallback) - 每个下游服务必须独立实例 + 命名,比如
Name: "payment-service-call";共用实例会导致 A 故障拖垮 B


















