https://sentinelguard.io/zh-cn/docs/golang/basic-api-usage.html

Sentinel Hystrix
隔离策略 信号量隔离 线程池隔离/信号量隔离
熔断降级策略 基于响应时间或失败比率 基于失败比率
实时指标实现 滑动窗口 滑动窗口(基于 RxJava)
规则配置 支持多种数据源 支持多种数据源
扩展性 多个扩展点 插件的形式
基于注解的支持 支持 支持
限流 基于 QPS,支持基于调用关系的限流 有限的支持
流量整形 支持慢启动、匀速器模式 不支持
系统负载保护 支持 不支持
控制台 开箱即用,可配置规则、查看秒级监控、机器发现等 不完善
常见框架的适配 Servlet、Spring Cloud、Dubbo、gRPC 等 Servlet、Spring Cloud Netflix

sentinel的qps限流

https://github.com/alibaba/sentinel-golang/blob/master/example/flow/qps/qps_limit_example.go

  1. package main
  2. import (
  3. "fmt"
  4. "log"
  5. "time"
  6. sentinel "github.com/alibaba/sentinel-golang/api"
  7. "github.com/alibaba/sentinel-golang/core/base"
  8. "github.com/alibaba/sentinel-golang/core/flow"
  9. )
  10. func main() {
  11. //先初始化sentinel
  12. err := sentinel.InitDefault()
  13. if err != nil {
  14. log.Fatalf("初始化sentinel 异常: %v", err)
  15. }
  16. //配置限流规则
  17. _, err = flow.LoadRules([]*flow.Rule{
  18. {
  19. Resource: "some-test",
  20. TokenCalculateStrategy: flow.Direct,
  21. ControlBehavior: flow.Reject, //直接拒绝
  22. Threshold: 1000, //100ms只能就已经来了1W的并发, 1s就是10W的并发
  23. StatIntervalInMs: 100,
  24. },
  25. {
  26. Resource: "some-test2",
  27. TokenCalculateStrategy: flow.Direct,
  28. ControlBehavior: flow.Reject, //直接拒绝
  29. Threshold: 1000,
  30. StatIntervalInMs: 100,
  31. },
  32. })
  33. if err != nil {
  34. log.Fatalf("加载规则失败: %v", err)
  35. }
  36. for i := 0; i < 12; i++ {
  37. e, b := sentinel.Entry("some-test", sentinel.WithTrafficType(base.Inbound))
  38. if b != nil {
  39. fmt.Println("限流了")
  40. } else {
  41. fmt.Println("检查通过")
  42. e.Exit()
  43. }
  44. }
  45. }

sentinel的预热和冷启动(WarmUp)

  1. package main
  2. import (
  3. "fmt"
  4. "log"
  5. "math/rand"
  6. "time"
  7. sentinel "github.com/alibaba/sentinel-golang/api"
  8. "github.com/alibaba/sentinel-golang/core/base"
  9. "github.com/alibaba/sentinel-golang/core/flow"
  10. )
  11. func main() {
  12. //先初始化sentinel
  13. err := sentinel.InitDefault()
  14. if err != nil {
  15. log.Fatalf("初始化sentinel 异常: %v", err)
  16. }
  17. var globalTotal int
  18. var passTotal int
  19. var blockTotal int
  20. ch := make(chan struct{})
  21. //配置限流规则
  22. _, err = flow.LoadRules([]*flow.Rule{
  23. {
  24. Resource: "some-test",
  25. TokenCalculateStrategy: flow.WarmUp, //冷启动策略
  26. ControlBehavior: flow.Reject, //直接拒绝
  27. Threshold: 1000,
  28. WarmUpPeriodSec: 30,
  29. },
  30. })
  31. if err != nil {
  32. log.Fatalf("加载规则失败: %v", err)
  33. }
  34. //我会在每一秒统计一次,这一秒只能 你通过了多少,总共有多少, block了多少, 每一秒会产生很多的block
  35. for i := 0; i < 100; i++ {
  36. go func() {
  37. for {
  38. globalTotal++
  39. e, b := sentinel.Entry("some-test", sentinel.WithTrafficType(base.Inbound))
  40. if b != nil {
  41. //fmt.Println("限流了")
  42. blockTotal++
  43. time.Sleep(time.Duration(rand.Uint64()%10) * time.Millisecond)
  44. } else {
  45. passTotal++
  46. time.Sleep(time.Duration(rand.Uint64()%10) * time.Millisecond)
  47. e.Exit()
  48. }
  49. }
  50. }()
  51. }
  52. go func() {
  53. var oldTotal int //过去1s总共有多少个
  54. var oldPass int //过去1s总共pass多少个
  55. var oldBlock int //过去1s总共block多少个
  56. for {
  57. oneSecondTotal := globalTotal - oldTotal
  58. oldTotal = globalTotal
  59. oneSecondPass := passTotal - oldPass
  60. oldPass = passTotal
  61. oneSecondBlock := blockTotal - oldBlock
  62. oldBlock = blockTotal
  63. time.Sleep(time.Second)
  64. fmt.Printf("total:%d, pass:%d, block:%d\n", oneSecondTotal, oneSecondPass, oneSecondBlock)
  65. }
  66. }()
  67. <-ch
  68. }

sentinel的Throttling配置策略

  1. package main
  2. import (
  3. "fmt"
  4. "log"
  5. "time"
  6. sentinel "github.com/alibaba/sentinel-golang/api"
  7. "github.com/alibaba/sentinel-golang/core/base"
  8. "github.com/alibaba/sentinel-golang/core/flow"
  9. )
  10. func main() {
  11. //先初始化sentinel
  12. err := sentinel.InitDefault()
  13. if err != nil {
  14. log.Fatalf("初始化sentinel 异常: %v", err)
  15. }
  16. //配置限流规则
  17. _, err = flow.LoadRules([]*flow.Rule{
  18. {
  19. Resource: "some-test",
  20. TokenCalculateStrategy: flow.Direct,
  21. ControlBehavior: flow.Throttling, //匀速通过
  22. Threshold: 10,
  23. StatIntervalInMs: 1000,
  24. },
  25. {
  26. Resource: "some-test2",
  27. TokenCalculateStrategy: flow.Direct,
  28. ControlBehavior: flow.Reject, //直接拒绝
  29. Threshold: 10,
  30. StatIntervalInMs: 1000,
  31. },
  32. })
  33. if err != nil {
  34. log.Fatalf("加载规则失败: %v", err)
  35. }
  36. for i := 0; i < 12; i++ {
  37. e, b := sentinel.Entry("some-test", sentinel.WithTrafficType(base.Inbound))
  38. if b != nil {
  39. fmt.Println("限流了")
  40. } else {
  41. fmt.Println("检查通过")
  42. e.Exit()
  43. }
  44. //匀速通过
  45. time.Sleep(11 * time.Millisecond)
  46. }
  47. }

sentinel的熔断接口-基于错误数—基于错误率和慢请求

基于错误数

https://github.com/alibaba/sentinel-golang/tree/master/example/circuitbreaker/error_count

  1. package main
  2. import (
  3. "errors"
  4. "fmt"
  5. "log"
  6. "math/rand"
  7. "time"
  8. sentinel "github.com/alibaba/sentinel-golang/api"
  9. "github.com/alibaba/sentinel-golang/core/circuitbreaker"
  10. "github.com/alibaba/sentinel-golang/core/config"
  11. "github.com/alibaba/sentinel-golang/logging"
  12. "github.com/alibaba/sentinel-golang/util"
  13. )
  14. type stateChangeTestListener struct {
  15. }
  16. func (s *stateChangeTestListener) OnTransformToClosed(prev circuitbreaker.State, rule circuitbreaker.Rule) {
  17. fmt.Printf("rule.steategy: %+v, From %s to Closed, time: %d\n", rule.Strategy, prev.String(), util.CurrentTimeMillis())
  18. }
  19. func (s *stateChangeTestListener) OnTransformToOpen(prev circuitbreaker.State, rule circuitbreaker.Rule, snapshot interface{}) {
  20. fmt.Printf("rule.steategy: %+v, From %s to Open, snapshot: %d, time: %d\n", rule.Strategy, prev.String(), snapshot, util.CurrentTimeMillis())
  21. }
  22. func (s *stateChangeTestListener) OnTransformToHalfOpen(prev circuitbreaker.State, rule circuitbreaker.Rule) {
  23. fmt.Printf("rule.steategy: %+v, From %s to Half-Open, time: %d\n", rule.Strategy, prev.String(), util.CurrentTimeMillis())
  24. }
  25. func main() {
  26. total := 0
  27. totalPass := 0
  28. totalBlock := 0
  29. totalErr := 0
  30. conf := config.NewDefaultConfig()
  31. // for testing, logging output to console
  32. conf.Sentinel.Log.Logger = logging.NewConsoleLogger()
  33. err := sentinel.InitWithConfig(conf)
  34. if err != nil {
  35. log.Fatal(err)
  36. }
  37. ch := make(chan struct{})
  38. // Register a state change listener so that we could observer the state change of the internal circuit breaker.
  39. circuitbreaker.RegisterStateChangeListeners(&stateChangeTestListener{})
  40. _, err = circuitbreaker.LoadRules([]*circuitbreaker.Rule{
  41. // Statistic time span=10s, recoveryTimeout=3s, maxErrorCount=50
  42. {
  43. Resource: "abc",
  44. Strategy: circuitbreaker.ErrorCount,
  45. RetryTimeoutMs: 3000, //3s只有尝试回复
  46. MinRequestAmount: 10, //静默数
  47. StatIntervalMs: 5000,
  48. Threshold: 50,
  49. },
  50. })
  51. if err != nil {
  52. log.Fatal(err)
  53. }
  54. logging.Info("[CircuitBreaker ErrorCount] Sentinel Go circuit breaking demo is running. You may see the pass/block metric in the metric log.")
  55. go func() {
  56. for {
  57. total++
  58. e, b := sentinel.Entry("abc")
  59. if b != nil {
  60. // g1 blocked
  61. totalBlock++
  62. fmt.Println("协程熔断了")
  63. time.Sleep(time.Duration(rand.Uint64()%20) * time.Millisecond)
  64. } else {
  65. totalPass++
  66. if rand.Uint64()%20 > 9 {
  67. totalErr++
  68. // Record current invocation as error.
  69. sentinel.TraceError(e, errors.New("biz error"))
  70. }
  71. // g1 passed
  72. time.Sleep(time.Duration(rand.Uint64()%20+10) * time.Millisecond)
  73. e.Exit()
  74. }
  75. }
  76. }()
  77. go func() {
  78. for {
  79. total++
  80. e, b := sentinel.Entry("abc")
  81. if b != nil {
  82. // g2 blocked
  83. totalBlock++
  84. time.Sleep(time.Duration(rand.Uint64()%20) * time.Millisecond)
  85. } else {
  86. // g2 passed
  87. totalPass++
  88. time.Sleep(time.Duration(rand.Uint64()%80) * time.Millisecond)
  89. e.Exit()
  90. }
  91. }
  92. }()
  93. go func() {
  94. for {
  95. time.Sleep(time.Second)
  96. fmt.Println(totalErr)
  97. }
  98. }()
  99. <-ch
  100. }

错误率

https://github.com/alibaba/sentinel-golang/tree/master/example/circuitbreaker/error_ratio

  1. package main
  2. import (
  3. "errors"
  4. "fmt"
  5. "log"
  6. "math/rand"
  7. "time"
  8. sentinel "github.com/alibaba/sentinel-golang/api"
  9. "github.com/alibaba/sentinel-golang/core/circuitbreaker"
  10. "github.com/alibaba/sentinel-golang/core/config"
  11. "github.com/alibaba/sentinel-golang/logging"
  12. "github.com/alibaba/sentinel-golang/util"
  13. )
  14. type stateChangeTestListener struct {
  15. }
  16. func (s *stateChangeTestListener) OnTransformToClosed(prev circuitbreaker.State, rule circuitbreaker.Rule) {
  17. fmt.Printf("rule.steategy: %+v, From %s to Closed, time: %d\n", rule.Strategy, prev.String(), util.CurrentTimeMillis())
  18. }
  19. func (s *stateChangeTestListener) OnTransformToOpen(prev circuitbreaker.State, rule circuitbreaker.Rule, snapshot interface{}) {
  20. fmt.Printf("rule.steategy: %+v, From %s to Open, snapshot: %.2f, time: %d\n", rule.Strategy, prev.String(), snapshot, util.CurrentTimeMillis())
  21. }
  22. func (s *stateChangeTestListener) OnTransformToHalfOpen(prev circuitbreaker.State, rule circuitbreaker.Rule) {
  23. fmt.Printf("rule.steategy: %+v, From %s to Half-Open, time: %d\n", rule.Strategy, prev.String(), util.CurrentTimeMillis())
  24. }
  25. func main() {
  26. total := 0
  27. totalPass := 0
  28. totalBlock := 0
  29. totalErr := 0
  30. conf := config.NewDefaultConfig()
  31. // for testing, logging output to console
  32. conf.Sentinel.Log.Logger = logging.NewConsoleLogger()
  33. err := sentinel.InitWithConfig(conf)
  34. if err != nil {
  35. log.Fatal(err)
  36. }
  37. ch := make(chan struct{})
  38. // Register a state change listener so that we could observer the state change of the internal circuit breaker.
  39. circuitbreaker.RegisterStateChangeListeners(&stateChangeTestListener{})
  40. _, err = circuitbreaker.LoadRules([]*circuitbreaker.Rule{
  41. // Statistic time span=10s, recoveryTimeout=3s, maxErrorCount=50
  42. {
  43. Resource: "abc",
  44. Strategy: circuitbreaker.ErrorRatio,
  45. RetryTimeoutMs: 3000, //3s只有尝试回复
  46. MinRequestAmount: 10, //静默数
  47. StatIntervalMs: 5000,
  48. Threshold: 0.4,
  49. },
  50. })
  51. if err != nil {
  52. log.Fatal(err)
  53. }
  54. logging.Info("[CircuitBreaker ErrorCount] Sentinel Go circuit breaking demo is running. You may see the pass/block metric in the metric log.")
  55. go func() {
  56. for {
  57. total++
  58. e, b := sentinel.Entry("abc")
  59. if b != nil {
  60. // g1 blocked
  61. totalBlock++
  62. fmt.Println("协程熔断了")
  63. time.Sleep(time.Duration(rand.Uint64()%20) * time.Millisecond)
  64. } else {
  65. totalPass++
  66. if rand.Uint64()%20 > 9 {
  67. totalErr++
  68. // Record current invocation as error.
  69. sentinel.TraceError(e, errors.New("biz error"))
  70. }
  71. // g1 passed
  72. time.Sleep(time.Duration(rand.Uint64()%40+10) * time.Millisecond)
  73. e.Exit()
  74. }
  75. }
  76. }()
  77. go func() {
  78. for {
  79. total++
  80. e, b := sentinel.Entry("abc")
  81. if b != nil {
  82. // g2 blocked
  83. totalBlock++
  84. time.Sleep(time.Duration(rand.Uint64()%20) * time.Millisecond)
  85. } else {
  86. // g2 passed
  87. totalPass++
  88. time.Sleep(time.Duration(rand.Uint64()%80) * time.Millisecond)
  89. e.Exit()
  90. }
  91. }
  92. }()
  93. go func() {
  94. for {
  95. time.Sleep(time.Second)
  96. fmt.Println(float64(totalErr) / float64(total))
  97. }
  98. }()
  99. <-ch
  100. }

慢请求

  1. package main
  2. import (
  3. "errors"
  4. "fmt"
  5. "log"
  6. "math/rand"
  7. "time"
  8. sentinel "github.com/alibaba/sentinel-golang/api"
  9. "github.com/alibaba/sentinel-golang/core/circuitbreaker"
  10. "github.com/alibaba/sentinel-golang/core/config"
  11. "github.com/alibaba/sentinel-golang/logging"
  12. "github.com/alibaba/sentinel-golang/util"
  13. )
  14. type stateChangeTestListener struct {
  15. }
  16. func (s *stateChangeTestListener) OnTransformToClosed(prev circuitbreaker.State, rule circuitbreaker.Rule) {
  17. fmt.Printf("rule.steategy: %+v, From %s to Closed, time: %d\n", rule.Strategy, prev.String(), util.CurrentTimeMillis())
  18. }
  19. func (s *stateChangeTestListener) OnTransformToOpen(prev circuitbreaker.State, rule circuitbreaker.Rule, snapshot interface{}) {
  20. fmt.Printf("rule.steategy: %+v, From %s to Open, snapshot: %.2f, time: %d\n", rule.Strategy, prev.String(), snapshot, util.CurrentTimeMillis())
  21. }
  22. func (s *stateChangeTestListener) OnTransformToHalfOpen(prev circuitbreaker.State, rule circuitbreaker.Rule) {
  23. fmt.Printf("rule.steategy: %+v, From %s to Half-Open, time: %d\n", rule.Strategy, prev.String(), util.CurrentTimeMillis())
  24. }
  25. func main() {
  26. conf := config.NewDefaultConfig()
  27. // for testing, logging output to console
  28. conf.Sentinel.Log.Logger = logging.NewConsoleLogger()
  29. err := sentinel.InitWithConfig(conf)
  30. if err != nil {
  31. log.Fatal(err)
  32. }
  33. ch := make(chan struct{})
  34. // Register a state change listener so that we could observer the state change of the internal circuit breaker.
  35. circuitbreaker.RegisterStateChangeListeners(&stateChangeTestListener{})
  36. _, err = circuitbreaker.LoadRules([]*circuitbreaker.Rule{
  37. // Statistic time span=10s, recoveryTimeout=3s, slowRtUpperBound=50ms, maxSlowRequestRatio=50%
  38. {
  39. Resource: "abc",
  40. Strategy: circuitbreaker.SlowRequestRatio,
  41. RetryTimeoutMs: 3000,
  42. MinRequestAmount: 10,
  43. StatIntervalMs: 5000,
  44. MaxAllowedRtMs: 50,
  45. Threshold: 0.5,
  46. },
  47. })
  48. if err != nil {
  49. log.Fatal(err)
  50. }
  51. logging.Info("[CircuitBreaker SlowRtRatio] Sentinel Go circuit breaking demo is running. You may see the pass/block metric in the metric log.")
  52. go func() {
  53. for {
  54. e, b := sentinel.Entry("abc")
  55. if b != nil {
  56. // g1 blocked
  57. time.Sleep(time.Duration(rand.Uint64()%20) * time.Millisecond)
  58. } else {
  59. if rand.Uint64()%20 > 9 {
  60. // Record current invocation as error.
  61. sentinel.TraceError(e, errors.New("biz error"))
  62. }
  63. // g1 passed
  64. time.Sleep(time.Duration(rand.Uint64()%80+10) * time.Millisecond)
  65. e.Exit()
  66. }
  67. }
  68. }()
  69. go func() {
  70. for {
  71. e, b := sentinel.Entry("abc")
  72. if b != nil {
  73. // g2 blocked
  74. time.Sleep(time.Duration(rand.Uint64()%20) * time.Millisecond)
  75. } else {
  76. // g2 passed
  77. time.Sleep(time.Duration(rand.Uint64()%80) * time.Millisecond)
  78. e.Exit()
  79. }
  80. }
  81. }()
  82. <-ch
  83. }

gin集成sentinel实现限流

商品列表页

  1. package initialize
  2. import (
  3. sentinel "github.com/alibaba/sentinel-golang/api"
  4. "github.com/alibaba/sentinel-golang/core/flow"
  5. "go.uber.org/zap"
  6. )
  7. func InitSentinel(){
  8. err := sentinel.InitDefault()
  9. if err != nil {
  10. zap.S().Fatalf("初始化sentinel 异常: %v", err)
  11. }
  12. //配置限流规则
  13. //这种配置应该从nacos中读取
  14. _, err = flow.LoadRules([]*flow.Rule{
  15. {
  16. Resource: "goods-list",
  17. TokenCalculateStrategy: flow.Direct,
  18. ControlBehavior: flow.Reject, //匀速通过
  19. Threshold: 20, //100ms只能就已经来了1W的并发, 1s就是10W的并发
  20. StatIntervalInMs: 6000,
  21. },
  22. })
  23. if err != nil {
  24. zap.S().Fatalf("加载规则失败: %v", err)
  25. }
  26. }