示例说明
重试适合偶发抖动,熔断适合持续故障——下游真挂了还继续调用是白白浪费资源与延迟。gobreaker 的三态闭环:闭合态正常放行并统计连续失败,ReadyToTrip 判定跳闸后进入打开态直接拒绝一切调用,冷却结束转半开态放限量试探请求,成功则回闭合、失败则回打开。
技术要点
- ReadyToTrip 自定义跳闸条件
- Timeout 控制打开态冷却时长
- OnStateChange 钩子接入告警
代码解读
newBreaker 配置连续五次失败跳闸、十秒计数窗口、五秒冷却与半开三请求试探;状态转换回调打印迁移轨迹。flakyService 按取模规律失败,十二次调用演示闭合到打开再到恢复的完整周期——跳闸后调用直接返回熔断错误,不再触达服务。
使用建议
阈值按下游容量与恢复周期调。半开试探量小防打瘫恢复中的服务。熔断打开期间走降级路径而不是裸抛错误。
代码示例
package main
import (
"errors"
"fmt"
"time"
"github.com/sony/gobreaker"
)
var errFlaky = errors.New("dependency flaky")
type flakyService struct{ failRate int }
func (s *flakyService) Call(n int) (string, error) {
if n%s.failRate == 0 {
return "", errFlaky
}
return "payload", nil
}
func newBreaker(name string) *gobreaker.CircuitBreaker {
return gobreaker.NewCircuitBreaker(gobreaker.Settings{
Name: name,
MaxRequests: 3, // 半开态最多放行 3 个试探
Interval: 10 * time.Second, // 闭合态计数窗口
Timeout: 5 * time.Second, // 打开态冷却时长
ReadyToTrip: func(counts gobreaker.Counts) bool {
return counts.ConsecutiveFailures >= 5
},
OnStateChange: func(name string, from gobreaker.State, to gobreaker.State) {
fmt.Printf("breaker %s: %s -> %s\n", name, from, to)
},
})
}
func guardedCall(cb *gobreaker.CircuitBreaker, svc *flakyService, n int) (string, error) {
out, err := cb.Execute(func() (interface{}, error) {
return svc.Call(n)
})
if err != nil {
return "", err
}
return out.(string), nil
}
func main() {
cb := newBreaker("flaky-api")
svc := &flakyService{failRate: 3}
for i := 1; i <= 12; i++ {
v, err := guardedCall(cb, svc, i)
fmt.Printf("call %02d -> value=%q err=%v\n", i, v, err)
}
}