熔断降级
最后更新于:2022-04-02 02:41:12
[TOC]
### 熔断降级
熔断器有三种状态:
1. Closed 状态:也是初始状态,该状态下,熔断器会保持闭合,对资源的访问直接通过熔断器的检查。
2. Open 状态:断开状态,熔断器处于开启状态,对资源的访问会被切断。
3. Half-Open 状态:半开状态,该状态下除了探测流量,其余对资源的访问也会被切断。探测流量指熔断器处于半开状态时,会周期性的允许一定数目的探测请求通过,如果探测请求能够正常的返回,代表探测成功,此时熔断器会重置状态到 Closed 状态,结束熔断;如果探测失败,则回滚到 Open 状态。
这三种状态之间的转换关系这里做一个更加清晰的解释:
1. 初始状态下,熔断器处于 Closed 状态。如果基于熔断器的统计数据表明当前资源触发了设定的阈值,那么熔断器会切换状态到 Open 状态;
2. Open 状态即代表熔断状态,所有请求都会直接被拒绝。熔断器规则中会配置一个熔断超时重试的时间,经过熔断超时重试时长后熔断器会将状态置为 Half-Open 状态,从而进行探测机制;
3. 处于 Half-Open 状态的熔断器会周期性去做探测。
三种熔断策略规则配置
```
// 慢调用比例规则
rule1 := &Rule{
Resource: "abc",
Strategy: SlowRequestRatio,
RetryTimeoutMs: 5000,
MinRequestAmount: 10,
StatIntervalMs: 10000,
MaxAllowedRtMs: 20,
Threshold: 0.1,
},
// 错误比例规则
rule1 := &Rule{
Resource: "abc",
Strategy: ErrorRatio,
RetryTimeoutMs: 5000,
MinRequestAmount: 10,
StatIntervalMs: 10000,
Threshold: 0.1,
},
// 错误计数规则
rule1 := &Rule{
Resource: "abc",
Strategy: ErrorCount,
RetryTimeoutMs: 5000,
MinRequestAmount: 10,
StatIntervalMs: 10000,
Threshold: 100,
},
```
main.go
```
package main
import (
"fmt"
"log"
"math/rand"
"time"
sentinel "github.com/alibaba/sentinel-golang/api"
"github.com/alibaba/sentinel-golang/core/circuitbreaker"
"github.com/alibaba/sentinel-golang/util"
)
type stateChangeTestListener struct {
}
func (s *stateChangeTestListener) OnTransformToClosed(prev circuitbreaker.State, rule circuitbreaker.Rule) {
fmt.Printf("rule.steategy: %+v, From %s to Closed, time: %d\n", rule.Strategy, prev.String(), util.CurrentTimeMillis())
}
func (s *stateChangeTestListener) OnTransformToOpen(prev circuitbreaker.State, rule circuitbreaker.Rule, snapshot interface{}) {
fmt.Printf("rule.steategy: %+v, From %s to Open, snapshot: %.2f, time: %d\n", rule.Strategy, prev.String(), snapshot, util.CurrentTimeMillis())
}
func (s *stateChangeTestListener) OnTransformToHalfOpen(prev circuitbreaker.State, rule circuitbreaker.Rule) {
fmt.Printf("rule.steategy: %+v, From %s to Half-Open, time: %d\n", rule.Strategy, prev.String(), util.CurrentTimeMillis())
}
func main() {
err := sentinel.InitDefault()
if err != nil {
log.Fatal(err)
}
ch := make(chan struct{})
// Register a state change listener so that we could observer the state change of the internal circuit breaker.
circuitbreaker.RegisterStateChangeListeners(&stateChangeTestListener{})
_, err = circuitbreaker.LoadRules([]*circuitbreaker.Rule{
// Statistic time span=10s, recoveryTimeout=3s, slowRtUpperBound=50ms, maxSlowRequestRatio=50%
{
Resource: "abc",
Strategy: circuitbreaker.SlowRequestRatio,
RetryTimeoutMs: 3000,
MinRequestAmount: 10,
StatIntervalMs: 10000, // 在 10s 的统计时间
MaxAllowedRtMs: 50, // 大于此时间的将视为错误链接
Threshold: 0.5, // 大于 MaxAllowedRtMs 比例大于50
},
// Statistic time span=10s, recoveryTimeout=3s, maxErrorRatio=50%
//{
// Resource: "abc",
// Strategy: circuitbreaker.ErrorRatio, //熔断策略:错误比例规则
// RetryTimeoutMs: 3000, //重试时间
// MinRequestAmount: 10, // 若当前统计周期内的请求数小于此值,即使达到熔断条件规则也不会触发
// StatIntervalMs: 10000, // 统计的时间窗口长度
// Threshold: 0.5,// 50% 也就是如果当前资源的慢调用比例如果高于Threshold,那么熔断器就会断开;否则保持闭合状态
//},
})
if err != nil {
log.Fatal(err)
}
//go func() {
// for {
// e, b := sentinel.Entry("abc")
// if b != nil {
// //fmt.Println("g1blocked")
// duration := time.Duration(rand.Uint64()%20) * time.Millisecond
// fmt.Printf("g1blocked %v \n",duration)
// time.Sleep(duration)
// } else {
// if rand.Uint64()%20 > 9 {
// // Record current invocation as error.
// sentinel.TraceError(e, errors.New("biz error"))
// }
// //fmt.Println("g1passed")
// duration := time.Duration(rand.Uint64()%80+10) * time.Millisecond
// fmt.Printf("g1passed %v\n",duration)
// time.Sleep(duration)
// e.Exit()
// }
// }
//}()
go func() {
for {
e, b := sentinel.Entry("abc")
if b != nil {
//fmt.Println("g2blocked")
duration := time.Duration(rand.Uint64()%20) * time.Millisecond
fmt.Printf("g2blocked %v \n",duration)
time.Sleep(duration)
} else {
//fmt.Println("g2passed")
duration := time.Duration(rand.Uint64()%80) * time.Millisecond
fmt.Printf("g2passed %v\n",duration)
time.Sleep(duration)
e.Exit()
}
}
}()
<-ch
}
```
';