Breaker

Overview

Breakers are also called smelters as a protective mechanism to protect services in service calls from too many requests.When an exception arises for a service in the service call link, the breaker rejects the service call request, thereby protecting other services in the service call link from being suppressed.

More prominent smelter algorithms are Hystrix and Sentinel, all of which determine the availability of services by the success rate and response time for statistical service calls.

go-zero has built-in the melting breaker component breaker.Breaker using a sliding window in go-zero, currently using 10 s as a window, with 40 barrels in a single window, and whether the data collected within the window is smelted using the google algorithre algorithm algorithm, refer to https://landing.google.com/sre/sre-book/chapters/handling-overload/#eq2101.

Usage

In breaker.Breaker’, Do, Do Acceptable, DoWithFallback, DoithFallbackAceptable Each of the four methods corresponds to different scenarios. And developers can call these methods directly through the breaker, or create a breaker instance that can be called either directly, and by name as a unique key to get/create a breaker instance.

Do

Do methods are default to judge if services are available by error rate, do not support indicator customization, and do not support error callbacks.

  1. type mockError struct {
  2. status int
  3. }
  4. func (e mockError) Error() string {
  5. return fmt.Sprintf("HTTP STATUS: %d", e.status)
  6. }
  7. func main() {
  8. for i := 0; i < 1000; i++ {
  9. if err := breaker.Do("test", func() error {
  10. return mockRequest()
  11. }); err != nil {
  12. println(err.Error())
  13. }
  14. }
  15. }
  16. func mockRequest() error {
  17. source := rand.NewSource(time.Now().UnixNano())
  18. r := rand.New(source)
  19. num := r.Intn(100)
  20. if num%4 == 0 {
  21. return nil
  22. } else if num%5 == 0 {
  23. return mockError{status: 500}
  24. }
  25. return errors.New("dummy")
  26. }

DoWithAcceptable

DoWithAcceptable table supports custom collection indicators, allows for autonomous control of what is acceptable and what needs to be added to the smelting indicator collection window.

  1. type mockError struct {
  2. status int
  3. }
  4. func (e mockError) Error() string {
  5. return fmt.Sprintf("HTTP STATUS: %d", e.status)
  6. }
  7. func main() {
  8. for i := 0; i < 1000; i++ {
  9. if err := breaker.DoWithAcceptable("test", func() error {
  10. return mockRequest()
  11. }, func(err error) bool { // 当 mock 的http 状态码部位500时都会被认为是正常的,否则加入错误窗口
  12. me, ok := err.(mockError)
  13. if ok {
  14. return me.status != 500
  15. }
  16. return false
  17. }); err != nil {
  18. println(err.Error())
  19. }
  20. }
  21. }
  22. func mockRequest() error {
  23. source := rand.NewSource(time.Now().UnixNano())
  24. r := rand.New(source)
  25. num := r.Intn(100)
  26. if num%4 == 0 {
  27. return nil
  28. } else if num%5 == 0 {
  29. return mockError{status: 500}
  30. }
  31. return errors.New("dummy")
  32. }

DoWithFallback

DoWithFallback defaults to use error rates to judge if the service is available, does not support indicator customization, but supports melting backslides.

  1. package main
  2. import (
  3. "errors"
  4. "fmt"
  5. "math/rand"
  6. "time"
  7. "github.com/zeromicro/go-zero/core/breaker"
  8. )
  9. type mockError struct {
  10. status int
  11. }
  12. func (e mockError) Error() string {
  13. return fmt.Sprintf("HTTP STATUS: %d", e.status)
  14. }
  15. func main() {
  16. for i := 0; i < 1000; i++ {
  17. if err := breaker.DoWithFallback("test", func() error {
  18. return mockRequest()
  19. }, func(err error) error {
  20. // 发生了熔断,这里可以自定义熔断错误转换
  21. return errors.New("当前服务不可用,请稍后再试")
  22. }); err != nil {
  23. println(err.Error())
  24. }
  25. }
  26. }
  27. func mockRequest() error {
  28. source := rand.NewSource(time.Now().UnixNano())
  29. r := rand.New(source)
  30. num := r.Intn(100)
  31. if num%4 == 0 {
  32. return nil
  33. } else if num%5 == 0 {
  34. return mockError{status: 500}
  35. }
  36. return errors.New("dummy")
  37. }

DoWithFallbackAcceptable

DoWithFallbackAcceptable supports collection indicator customization and melting backback.

  1. package main
  2. import (
  3. "errors"
  4. "fmt"
  5. "math/rand"
  6. "time"
  7. "github.com/zeromicro/go-zero/core/breaker"
  8. )
  9. type mockError struct {
  10. status int
  11. }
  12. func (e mockError) Error() string {
  13. return fmt.Sprintf("HTTP STATUS: %d", e.status)
  14. }
  15. func main() {
  16. for i := 0; i < 1000; i++ {
  17. if err := breaker.DoWithFallbackAcceptable("test", func() error {
  18. return mockRequest()
  19. }, func(err error) error {
  20. //发生了熔断,这里可以自定义熔断错误转换
  21. return errors.New("当前服务不可用,请稍后再试")
  22. }, func(err error) bool { // 当 mock 的http 状态码部位500时都会被认为是正常的,否则加入错误窗口
  23. me, ok := err.(mockError)
  24. if ok {
  25. return me.status != 500
  26. }
  27. return false
  28. }); err != nil {
  29. println(err.Error())
  30. }
  31. }
  32. }
  33. func mockRequest() error {
  34. source := rand.NewSource(time.Now().UnixNano())
  35. r := rand.New(source)
  36. num := r.Intn(100)
  37. if num%4 == 0 {
  38. return nil
  39. } else if num%5 == 0 {
  40. return mockError{status: 500}
  41. }
  42. return errors.New("dummy")
  43. }

The above method is to fetch/create a breaker instance with the same name as the smelter that belongs to a smelter control. If a customized breaker configuration is required, you can create a breaker instance through the NewBreaker method, where you can precisely control whether the situation is relaxed or refused.

  1. // 熔断器名称是一个可选参数,当不传时,默认采用一个随机值
  2. opt := breaker.WithName("test")
  3. b := breaker.NewBreaker(opt)
  4. // 快捷调用
  5. //b.Do()
  6. //b.DoWithAcceptable()
  7. //b.DoWithFallback()
  8. //b.DoWithFallbackAcceptable()
  9. // 自主控制放行/拒绝 case
  10. // mockRequest := func(status int) error {
  11. // p, err := b.Allow()
  12. // if err != nil {
  13. // return err
  14. // }
  15. // if status == 200 {
  16. // p.Accept()
  17. // }
  18. // p.Reject(fmt.Sprintf("HTTP STATUS: %d", status))
  19. // return nil
  20. // }
  21. // for i := 0; i < 100; i++ {
  22. // var mockStatus int
  23. // if i%10 == 0 {
  24. // mockStatus = 500
  25. // }
  26. // if err := mockRequest(mockStatus)(); err != nil {
  27. // fmt.Println(err)
  28. // }
  29. // }

Used in HTTP & gRPC

In go-zero, the developer does not need to smelt the request individually. This function is integrated into the framework, so the developer does not need to relate.

HTTP uses request method + routing as a statistical dimension using HTTP status code 500 as a wrong collection indicator, reference breakerhandler.go

The gRPC client uses the rpc method as the statistical dimension using the rpc method error code codes.DeadlineExeed, codes.internal, codes. Available from, codes.DataLoss, codes.Unimplemented as error collection indicator, refer to breakerinterceptor.go

gRPC server is used as a statistical dimension by rpc method, using grpc error as a wrong collection indicator, reference breakerinterceptor.go

References