This article is introduced to you by the golang tutorial column about Sentinel current limiting and circuit breaker downgrading. The content includes an introduction to current limiting and circuit breaker, as well as alibaba open source Sentinel, installation, and practical introduction. I hope it will be helpful to friends in need. !
What is current limiting\circuit break\downgrade
Current limiting: In our acquired system, if a large amount of traffic suddenly enters that day, our service can only handle 2k requests at the same time. Suddenly, 5k requests come
. This is Isn’t the pressure on the server terrible? This may directly cause the server to shut down and crash, causing the original 2K processing volume to be unable to be processed. At this time, we need to limit the current. The function of current limiting is When the number of visits reaches the highest level on the server, it is much better to not process redundant requests
than to directly hang up the server. For example, during Double Eleven, when we want to place an order, we will see something like "The request is busy, please try again later!".
Circuit breaker: I believe everyone is familiar with the circuit breaker. It is equivalent to a switch that can prevent traffic from passing through. For example, a fuse will blow when the current is too high, thus preventing damage to components.
Service circuit breaker refers to the caller accessing the service through a circuit breaker as a proxy. The circuit breaker will continue to observe the success and failure status returned by the service.
When the failure exceeds the set threshold When the circuit breaker is open, requests cannot actually access the service.
Usage scenariosWhen the service fails or is upgraded, let the client fail quickly
Scenario) When overload or slow response occurs, requests for some non-core interfaces and data are temporarily abandoned internally, and a
Sentinel is an open source project of Alibaba. It provides multiple dimensions such as flow control, circuit breaker degradation, and system load protection to ensure the stability of services. sex.
Official website: github.com/alibaba/Sentinel/wiki
Sentinel was born in Alibaba in 2012, and its main goal is traffic control. From 2013 to 2017, Sentinel developed rapidly and became a basic component of all Alibaba microservices. It is used in more than 6000 applications, covering almost all core e-commerce scenarios. In 2018, Sentinel evolved into an open source project. In 2020, Sentinel Golang was released. Features:
Rich application scenarios: Sentinel has undertaken the core scenarios of Alibaba’s Double Eleven promotion traffic in the past 10 years, such as flash sales (i.e.
burst Traffic control within the range that the system capacity can bear), message peak shaving and valley filling, cluster traffic control, real-time fusing of downstream unavailable applications, etc.
Complete real-time monitoring: Sentinel also provides real-time monitoring functions. You can see the second-level data of a single machine connected to the application in the console, and even the summary operation status of a cluster with less than 500 machines.
* Broad Ecology*
History of SentinelIn 2012, Sentinel was born, its main function is inlet flow control .
From 2013 to 2017, Sentinel developed rapidly within Alibaba Group and became a basic technology module, covering all core scenarios. Sentinel has thus accumulated a large number of traffic consolidation scenarios and production practices.
Official website documentation
Installation:go get github.com/alibaba/sentinel-golang/api
Go current limiting practice
qps current limit
package main import ( "fmt" "log" sentinel "github.com/alibaba/sentinel-golang/api" "github.com/alibaba/sentinel-golang/core/base" "github.com/alibaba/sentinel-golang/core/flow" ) func main() { //基于sentinel的qps限流 //必须初始化 err := sentinel.InitDefault() if err != nil { log.Fatalf("Unexpected error: %+v", err) } //配置限流规则:1秒内通过10次 _, err = flow.LoadRules([]*flow.Rule{ { Resource: "some_test", TokenCalculateStrategy: flow.Direct, ControlBehavior: flow.Reject, //超过直接拒绝 Threshold: 10, //请求次数 StatIntervalInMs: 1000, //允许时间内 }, }) if err != nil { log.Fatalf("Unexpected error: %+v", err) return } for i := 0; i < 12; i++ { e, b := sentinel.Entry("some_test", sentinel.WithTrafficType(base.Inbound)) if b != nil { fmt.Println("限流了") } else { fmt.Println("检查通过") e.Exit() } } }
Print result:
检查通过 检查通过 检查通过 检查通过 检查通过 检查通过 检查通过 检查通过 检查通过 检查通过 限流了 限流了
Thrnotting
package main import ( "fmt" "log" "time" sentinel "github.com/alibaba/sentinel-golang/api" "github.com/alibaba/sentinel-golang/core/base" "github.com/alibaba/sentinel-golang/core/flow" ) func main() { //基于sentinel的qps限流 //必须初始化 err := sentinel.InitDefault() if err != nil { log.Fatalf("Unexpected error: %+v", err) } //配置限流规则 _, err = flow.LoadRules([]*flow.Rule{ { Resource: "some_test", TokenCalculateStrategy: flow.Direct, ControlBehavior: flow.Throttling, //匀速通过 Threshold: 10, //请求次数 StatIntervalInMs: 1000, //允许时间内 }, }) if err != nil { log.Fatalf("Unexpected error: %+v", err) return } for i := 0; i < 12; i++ { e, b := sentinel.Entry("some_test", sentinel.WithTrafficType(base.Inbound)) if b != nil { fmt.Println("限流了") } else { fmt.Println("检查通过") e.Exit() } time.Sleep(time.Millisecond * 100) } }
检查通过 检查通过 检查通过 检查通过 检查通过 检查通过 检查通过 检查通过 检查通过 检查通过 检查通过 检查通过
Warrm_up
package main import ( "fmt" "log" "math/rand" "time" sentinel "github.com/alibaba/sentinel-golang/api" "github.com/alibaba/sentinel-golang/core/base" "github.com/alibaba/sentinel-golang/core/flow" ) func main() { //先初始化sentinel err := sentinel.InitDefault() if err != nil { log.Fatalf("初始化sentinel 异常: %v", err) } var globalTotal int var passTotal int var blockTotal int ch := make(chan struct{}) //配置限流规则 _, err = flow.LoadRules([]*flow.Rule{ { Resource: "some-test", TokenCalculateStrategy: flow.WarmUp, //冷启动策略 ControlBehavior: flow.Reject, //直接拒绝 Threshold: 1000, WarmUpPeriodSec: 30, }, }) if err != nil { log.Fatalf("加载规则失败: %v", err) } //我会在每一秒统计一次,这一秒只能 你通过了多少,总共有多少, block了多少, 每一秒会产生很多的block for i := 0; i < 100; i++ { go func() { for { globalTotal++ e, b := sentinel.Entry("some-test", sentinel.WithTrafficType(base.Inbound)) if b != nil { //fmt.Println("限流了") blockTotal++ time.Sleep(time.Duration(rand.Uint64()%10) * time.Millisecond) } else { passTotal++ time.Sleep(time.Duration(rand.Uint64()%10) * time.Millisecond) e.Exit() } } }() } go func() { var oldTotal int //过去1s总共有多少个 var oldPass int //过去1s总共pass多少个 var oldBlock int //过去1s总共block多少个 for { oneSecondTotal := globalTotal - oldTotal oldTotal = globalTotal oneSecondPass := passTotal - oldPass oldPass = passTotal oneSecondBlock := blockTotal - oldBlock oldBlock = blockTotal time.Sleep(time.Second) fmt.Printf("total:%d, pass:%d, block:%d\n", oneSecondTotal, oneSecondPass, oneSecondBlock) } }() <-ch }
Print result: Gradually Reaching 1k, fluctuating up and down at the 1k position
total:11, pass:9, block:0 total:21966, pass:488, block:21420 total:21793, pass:339, block:21414 total:21699, pass:390, block:21255 total:21104, pass:393, block:20654 total:21363, pass:453, block:20831 total:21619, pass:491, block:21052 total:21986, pass:533, block:21415 total:21789, pass:594, block:21123 total:21561, pass:685, block:20820 total:21663, pass:873, block:20717 total:20904, pass:988, block:19831 total:21500, pass:996, block:20423 total:21769, pass:1014, block:20682 total:20893, pass:1019, block:19837 total:21561, pass:973, block:20524 total:21601, pass:1014, block:20517 total:21475, pass:993, block:20420 total:21457, pass:983, block:20418 total:21397, pass:1024, block:20320 total:21690, pass:996, block:20641 total:21526, pass:991, block:20457 total:21779, pass:1036, block:20677
Go circuit breaker practice
Here we introduce an incorrect number, view the detailed circuit breaker mechanism
error_count package main import ( "errors" "fmt" "log" "math/rand" "time" sentinel "github.com/alibaba/sentinel-golang/api" "github.com/alibaba/sentinel-golang/core/circuitbreaker" "github.com/alibaba/sentinel-golang/core/config" "github.com/alibaba/sentinel-golang/logging" "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: %d, 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() { //基于连接数的降级模式 total := 0 totalPass := 0 totalBlock := 0 totalErr := 0 conf := config.NewDefaultConfig() // for testing, logging output to console conf.Sentinel.Log.Logger = logging.NewConsoleLogger() err := sentinel.InitWithConfig(conf) 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, maxErrorCount=50 { Resource: "abc", Strategy: circuitbreaker.ErrorCount, RetryTimeoutMs: 3000, //3s只有尝试回复 MinRequestAmount: 10, //静默数 StatIntervalMs: 5000, Threshold: 50, }, }) if err != nil { log.Fatal(err) } logging.Info("[CircuitBreaker ErrorCount] Sentinel Go circuit breaking demo is running. You may see the pass/block metric in the metric log.") go func() { for { total++ e, b := sentinel.Entry("abc") if b != nil { // g1 blocked totalBlock++ fmt.Println("协程熔断了") time.Sleep(time.Duration(rand.Uint64()%20) * time.Millisecond) } else { totalPass++ if rand.Uint64()%20 > 9 { totalErr++ // Record current invocation as error. sentinel.TraceError(e, errors.New("biz error")) } // g1 passed time.Sleep(time.Duration(rand.Uint64()%20+10) * time.Millisecond) e.Exit() } } }() go func() { for { total++ e, b := sentinel.Entry("abc") if b != nil { // g2 blocked totalBlock++ time.Sleep(time.Duration(rand.Uint64()%20) * time.Millisecond) } else { // g2 passed totalPass++ time.Sleep(time.Duration(rand.Uint64()%80) * time.Millisecond) e.Exit() } } }() go func() { for { time.Sleep(time.Second) fmt.Println(totalErr) } }() <-ch }
The above is the detailed content of What are current limiting and fusing? Detailed explanation of Sentinel current limiting fuse degradation. For more information, please follow other related articles on the PHP Chinese website!