当前位置:   article > 正文

Golang的微服务组件之限流器与熔断器_golang http 熔断

golang http 熔断

Golang的微服务组件之限流器与熔断器_迈克 Let's Go的博客-CSDN博客icon-default.png?t=M5H6https://blog.csdn.net/Edu_enth/article/details/103800551hystrix-go 类库 实现过载保护 - 熔断与降级_慕课手记 (imooc.com)icon-default.png?t=M5H6https://www.imooc.com/article/320260【GO】golang 降级|熔断|限流实战 - 简书 (jianshu.com)icon-default.png?t=M5H6https://www.jianshu.com/p/be5c139c11e3

简介

微服务架构里面一个很常见的问题就是服务之间的延迟和通信失败问题,极端的情况下,甚至会因为某个服务的性能下降或者故障宕机,导致访问超时,层层传递,引发雪崩,最终导致整个系统崩溃,而限流器和熔断器(这两个组件都是客户端的)能很好的解决这个问题,提高系统的可靠性和稳定性

限流器

限流器,从字面上理解就是用来限制流量,有时候流量突增(可预期的比如“双11”,不可预期的微博的热门话题等),会将后端服务压垮,甚至直接宕机,使用限流器能限制访问后端的流量,起到一个保护作用,被限制的流量,可以根据具体的业务逻辑去处理,直接返回错误或者返回默认值等等

golang 提供了拓展库(golang.org/x/time/rate)提供了限流器组件,用法上也很简单直观,通过下面这段代码就可以创建一个限流器

  1. //800ms 产生 1 个 token,最多缓存 1 个 token,如果缓存满了,新的 token 会被丢弃
  2. limiter := rate.NewLimiter(rate.Every(time.Duration(800)*time.Millisecond), 1)

限流器提供三种使用方式,Allow, Wait, Reserve

  • Allow: 返回是否有 token,没有 token 返回 false,或者消耗 1 个 token 返回 true
  • Wait: 阻塞等待,知道取到 1 个 token
  • Reserve: 返回 token 信息,Allow 其实相当于 Reserve().OK,此外还会返回需要等待多久才有新的 token

一般使用 Wait 的场景会比较多一些

  1. if err := limiter.Wait(context.Background()); err != nil {
  2. panic(err)
  3. }
  4. // do you business logic

熔断器

和限流器对依赖服务的保护机制不一样,熔断器是当依赖的服务已经出现故障时,为了保证自身服务的正常运行不再访问依赖的服务,防止雪崩效应

熔断器有三种状态:

  • 关闭状态:服务正常,并维护一个失败率统计,当失败率达到阀值时,转到开启状态
  • 开启状态:服务异常,调用 fallback 函数,一段时间之后,进入半开启状态
  • 半开启装态:尝试恢复服务,失败率高于阀值,进入开启状态,低于阀值,进入关闭状态
    github.com/afex/hystrix-go,提供了 go 熔断器实现,使用上面也很方便,首先创建一个熔断器
  1. hystrix.ConfigureCommand(
  2. "addservice", // 熔断器名字,可以用服务名称命名,一个名字对应一个熔断器,对应一份熔断策略
  3. hystrix.CommandConfig{
  4. Timeout: 100, // 超时时间 100ms
  5. MaxConcurrentRequests: 2, // 最大并发数,超过并发返回错误
  6. RequestVolumeThreshold: 4, // 请求数量的阀值,用这些数量的请求来计算阀值
  7. ErrorPercentThreshold: 25, // 错误率阀值,达到阀值,启动熔断,25%
  8. SleepWindow: 1000, // 熔断尝试恢复时间,1000ms
  9. },
  10. )

提供了阻塞和非阻塞两种使用方式,完整代码可以参考如下链接: 代码

阻塞使用 Do 方法,返回一个 err

  1. err := hystrix.Do("addservice", func() error {
  2. // 正常业务逻辑,一般是访问其他资源
  3. var err error
  4. // 设置总体超时时间 10 ms 超时
  5. ctx, cancel := context.WithTimeout(context.Background(), time.Duration(50*time.Millisecond))
  6. defer cancel()
  7. res, err = client.Add(
  8. ctx, req,
  9. // 这里可以再次设置重试次数,重试时间,重试返回码
  10. grpc_retry.WithMax(3),
  11. grpc_retry.WithPerRetryTimeout(time.Duration(5)*time.Millisecond),
  12. grpc_retry.WithCodes(codes.DeadlineExceeded),
  13. )
  14. return err
  15. }, func(err error) error {
  16. // 失败处理逻辑,访问其他资源失败时,或者处于熔断开启状态时,会调用这段逻辑
  17. // 可以简单构造一个response返回,也可以有一定的策略,比如访问备份资源
  18. // 也可以直接返回 err,这样不用和远端失败的资源通信,防止雪崩
  19. // 这里因为我们的场景太简单,所以我们可以在本地在作一个加法就可以了
  20. fmt.Println(err)
  21. res = &addservice.AddResponse{V: req.A + req.B}
  22. return nil
  23. })

非阻塞方法使用 Go 方法,返回一个 error 的 channel,建议在有多个资源需要并发访问的场景下是使用

  1. errc1 := hystrix.Go("addservice", func() error {
  2. var err error
  3. ctx, cancel := context.WithTimeout(context.Background(), time.Duration(50*time.Millisecond))
  4. defer cancel()
  5. res1, err = client.Add(ctx, req)
  6. if err == nil {
  7. success <- struct{}{}
  8. }
  9. return err
  10. }, nil)
  11. // 有 fallback 处理
  12. errc2 := hystrix.Go("addservice", func() error {
  13. var err error
  14. ctx, cancel := context.WithTimeout(context.Background(), time.Duration(50*time.Millisecond))
  15. defer cancel()
  16. res2, err = client.Add(ctx, req)
  17. if err == nil {
  18. success <- struct{}{}
  19. }
  20. return err
  21. }, func(err error) error {
  22. fmt.Println(err)
  23. res2 = &addservice.AddResponse{V: req.A + req.B}
  24. success <- struct{}{}
  25. return nil
  26. })
  27. for i := 0; i < 2; i++ {
  28. select {
  29. case <-success:
  30. fmt.Println("success", i)
  31. case err := <-errc1:
  32. fmt.Println("err1:", err)
  33. case err := <-errc2:
  34. // 这个分支永远不会走到,因为熔断机制里面永远不会返回错误
  35. fmt.Println("err2:", err)
  36. }
  37. }

参考链接

测试代码
Circuit Breaker Pattern
hystrix-go

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/317847
推荐阅读
相关标签
  

闽ICP备14008679号