企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
[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, }, ``` <details> <summary>main.go</summary> ``` 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 } ``` </details> <br/>