熔断是指在在调用其他服务时,其他服务发生错误时上游主动关闭或限制对其他服务的请求。
原理
通常熔断器分为三个时期:CLOSED,OPEN,HALFOPEN
RPC 正常时,为 CLOSED;
当 RPC 错误增多时,熔断器会被触发,进入 OPEN;
OPEN 后经过一定的冷却时间,熔断器变为 HALFOPEN;
HALFOPEN 时会对下游进行一些有策略的访问,然后根据结果决定是变为 CLOSED,还是 OPEN;
常见熔断器:
https://github.com/sony/gobreaker,此熔断器为索尼公司开源,star比较多。
hystrix熔断器地址:github.com/afex/hystrix-go/hystrix。
下面学习使用hystrix:
注:此熔断器只有关闭和打开状态
测试:
//初始化熔断器
func init() {
log.SetFlags(log.Lmicroseconds)
hystrix.ConfigureCommand(
"TestHystrix",
hystrix.CommandConfig{
Timeout: 2000, // 超时时间 100ms
MaxConcurrentRequests: 2, // 最大并发数,超过并发返回错误
// 请求数量的阀值,最近10s内请求数量达到此值后才会计算是否开启熔断器
RequestVolumeThreshold: 10,
ErrorPercentThreshold: 25, // 错误率阀值,达到阀值,启动熔断,25%
SleepWindow: 2000, // 熔断尝试恢复时间,2000ms
},
)
}
//调用超时
func TestHystrixTimeOut(t *testing.T) {
//阻塞调用,当调用业务逻辑方法时,会阻塞直到返回
hystrix.Do("TestHystrix", func() error {
log.Println("Do开始调用业务逻辑")
time.Sleep(time.Second * 3 )
return errors.New("ddd")
}, func(err error) error {
return nil
})
hystrix.Go("TestHystrix", func() error {
log.Println("Go开始调用业务逻辑")
time.Sleep(time.Second * 3 )
return nil
}, func(err error) error {
log.Println("Go失败,一般做降级处理", err)
return nil
})
time.Sleep(time.Second * 5)
}
//最大请求数
func TestHystrixMaxRequest(t *testing.T) {
//并发数最大,0 1调用,0执行成功,1执行失败。2 3 4达到最大并发数,并未调用,直接执行失败
for i := 0; i < 5; i++ {
tag := i
hystrix.Go("TestHystrix", func() error {
log.Println(tag,"开始调用业务逻辑")
time.Sleep(time.Second * 1 )
if tag == 1 {
return errors.New("error............")
}else{
return nil
}
}, func(err error) error {
log.Println(tag,"失败,一般做降级处理", err)
return nil
})
}
time.Sleep(time.Second * 5)
}
//测试请求熔断
func TestHystrixPercentThreshold(t *testing.T) {
success := 0
failed := 0
//模拟30%调用失败率
for i := 0; i < 200; i++ {
tag := i
rand.Seed(time.Now().UnixNano())
fail := rand.Int() % 1000 < 300
if fail {
failed ++
}else{
success ++
}
str := "当前失败率:" + strconv.Itoa(int(float32(failed) / float32(failed + success) * 100))
hystrix.Go("TestHystrix", func() error {
if fail {
// log.Println(tag,"开始调用业务逻辑, 业务失败 当前", str)
return errors.New("error............" + strconv.Itoa(tag) + " " +str)
}else{
log.Println(tag,"开始调用业务逻辑, 业务成功", str)
return nil
}
}, func(err error) error {
log.Println(tag,"失败,一般做降级处理", err, " 预测实际逻辑执行成功:", !fail, str)
return nil
})
time.Sleep(time.Millisecond * 300)
}
time.Sleep(time.Second * 10)
}
此测试中,可以看到,达到10s内请求数时,失败率达到配置的25%,触发熔断,熔断后达到恢复时间2s后请求正常。