美文网首页
Micro实战:断路器和限流器

Micro实战:断路器和限流器

作者: golang推广大使 | 来源:发表于2020-03-10 00:13 被阅读0次

    今天的主题是断路器和限流器。

    断路器和限流器在大规模系统架构中是非常重要的滑条。当我们开始把单体系统拆分为分布式微服务时,这些话题变得更加重要。如果没有断路器和限流器,单个组件的故障很容易导致雪崩效应。这可能导致整个系统崩溃。

    在Micro的可插拔架构下,可以很容易的引入上述机制。我们知道Micro支持使用中间件包装请求。这些中间件中最重要的两个是:

    • micro.WrapClient, 用于包装出站请求,也称为客户端包装
    • micro.WrapHandler, 用于包装入站请求,也称为服务端包装
      这两种类型的中间件分别适用于断路器和限流器的场景。下面我们以示例说明如何使用这些中间件来提供系统的鲁棒性。

    断路器

    通常,这种通用功能都不需要我们自己开发。社区中已经有出色的开源库。例如:hystrix-go,gobreaker.
    此外,Micro还提供了适用于上述库的插件,例如hystrix插件和gobreaker插件。
    借助这些插件,在Mirco中石油Circuit Breaker变得非常容易。以hystrix为例:

    import (
    ...
      "github.com/micro/go-plugins/wrapper/breaker/hystrix"
    ...
    )
    func main(){
    ...
      // New Service
      service := micro.NewService(
         micro.Name("com.foo.breaker.example"),
         micro.WrapClient(hystrix.NewClientWrapper()),
      )
      // Initialise service
      service.Init()
    ...
    }
    

    我们要做的就是在service创建过程中分配hystrix插件,
    从现在开始,该插件将跟踪对远程服务的所有调用。当请求超时或并发数达到限制时,错误将立即返回给调用方。
    那么,并发和超时的默认限制是什么?答案在于hystrix-go插件的源代码。查看github.com/afex/hystrix-go/hystrix/settings.go,您会看到几个包级变量:

    ... 
       // DefaultTimeout是等待命令完成的时间,以毫秒为单位
       DefaultTimeout = 1000 
       // DefaultMaxConcurrent是可以同时运行多少个相同类型的命令
       DefaultMaxConcurrent = 10 
    ...
    

    因此,默认超时为1秒,默认并发限制为10。

    注意:除了这两个以外,还有更多设置,但是对所有这些设置的讨论不在本文讨论范围之内。如果您有兴趣,可以访问hystrix-go库的官方网站以获取详细的文档。

    如果默认设置不符合我们的要求,则可以如下进行修改:

    import(
    ... 
      hystrixGo “github.com/afex/hystrix-go/hystrix”
       “github.com/micro/go-plugins/wrapper/breaker/hystrix” 
    ... 
    )
    func main(){ 
    ... 
      //新服务
        service:= micro.NewService(
         micro.Name(“ com.foo.breaker.example”),
         micro.WrapClient(hystrix.NewClientWrapper()),
      )
      //初始化服务
      service.Init()
      hystrix.DefaultMaxConcurrent = 3 //将并发更改为3 
      hystrix.DefaultTimeout = 200 //将超时更改为200毫秒
    ... 
    }
    

    如代码所示,我们可以更改默认超时和并发限制
    您可能对DefaultMaxConcurrent有疑问:它的范围是什么?假设有3个服务,每个服务有3种不同的方法。我们想同时调用所有这些方法。这是否意味着我们必须将DefaultMaxConcurrent设置为大于3 * 3的数字才能实现完全并发?
    要回答这个问题,需要指出两点:
    首先,DefaultMaxConcurrent的目标是什么?从hystrix文档中可以看到,这是hystrix中的命令:
    DefaultMaxConcurrent是可以同时运行多少个相同类型的命令
    接下来,您需要了解hystrix插件如何处理不同方法和命令之间的映射。查看github.com/micro/go-plugins/wrapper/breaker/hystrix/hystrix.go,您会发现相关代码如下:

    import(
      "github.com/afex/hystrix-go/hystrix"
      ... 
    )
    ... 
    func (c *clientWrapper) Call(ctx context.Context,req client.Request,rsp interface{},opts... client .CallOption) error{ 
      return hystrix.Do(req.Service()+"." + req.Endpoint(),func() error{ 
          return c.Client.Call(ctx,req,rsp,opts ...)
       }} ,nil)
    } 
    ...
    

    请注意req.Service () + “.” + Req.Endpoint (),它是hystrix 的命令。并且该命令不包含节点信息,这意味着对于同一服务,单节点部署或多节点部署没有区别,所有节点共享一个限制。
    在这一点上很明显:每种服务的每种方法都是独立计数的,并且不会相互影响。无论节点数量如何,DefaultMaxConcurrent的范围都是方法级别。
    实际上,不同的方法可能需要不同的限制。如何实现呢?从上面的源代码中,我们知道服务方法已映射到hystrix 命令,并且hystrix通过hystrix.ConfigureCommand以下命令支持对不同命令的独立控制:

    ... 
    hystrix.ConfigureCommand("com.serviceA.methodFoo",
       hystrix.CommandConfig{
          MaxConcurrentRequests: 50,
          Timeout:               10,
       })
    hystrix.ConfigureCommand("com.serviceB.methodBar",
       hystrix.CommandConfig{
          Timeout: 60,
       })
    ...
    

    使用以上代码,我们为不同的方法设置了不同的限制。如果hystrix.CommandConfig未指定该结构的任何字段,则将使用系统默认值。
    摘要:断路器在客户端上起作用。使用适当的阈值,可以确保客户端资源不会耗尽。即使它所依赖的服务不正常,客户端也将迅速返回错误,而不是让调用者等待很长时间。

    限流器

    与断路器类似,速率限制也是分布式系统中的常用功能。不同之处在于,Rate Limiter在服务器端生效,其作用是保护服务器:请求处理的速度达到预设的限制后,服务器将不再接收新请求,直到处理中的请求完成为止。速率限制器可以避免服务器因大量请求而崩溃。

    打个比方:假设我们经营一家餐厅,可容纳10位客人。如果同时有100位客人共进晚餐,那么最好的处理方法是选择前10位客人并告知其他90位客人:我们目前无法提供服务,请改回第二天。尽管这90位客人不满意,但我们保证至少前10位客人可以享用一顿美餐。

    没有Rate Limiter,结果是有100位客人进入餐厅,厨房太忙了,所有客人都无处可坐。没有人可以得到服务。整个餐厅最终瘫痪了。

    在Micro中使用Rate Limiter也非常简单。我们只需要一行代码即可实现这一目标。当前有两个Rate Limiter插件。本文以uber rate limiter插件为例(当然,如果现有插件不满足要求,您可以随时自行开发更合适的插件)。让我们修改源文件hello-srv / main.go

    package main
    import (
    ...
       limiter "github.com/micro/go-plugins/wrapper/ratelimiter/uber"
    ...
    )
    func main() {
       const QPS = 100
       // New Service
       service := micro.NewService(
          micro.Name("com.foo.srv.hello"),
          micro.Version("latest"),
          micro.WrapHandler(limiter.NewHandlerWrapper(QPS)),
       )
    ...
    }
    

    上面的代码将服务器端速率限制器添加到hello-srv,QPS上限为100。此服务中所有处理程序的方法都共享此限制。换句话说,此限制的范围是服务级别。

    相关文章

      网友评论

          本文标题:Micro实战:断路器和限流器

          本文链接:https://www.haomeiwen.com/subject/cgmvdhtx.html