zoukankan      html  css  js  c++  java
  • go-kit 微服务 服务熔断(hystrix-go 实现)

    go-kit 微服务 服务熔断(hystrix-go 实现)

    • 对客户端请求login方法添加熔断

    Hystrix

    • 在微服务架构中,每个服务都是相互关联的,比如我们下单服务和扣钱服务是分开的,现在扣钱服务出现的bug不能正常服务
    • Hystrix可以让我们在在微服务架构中对服务间的调用进行控制,加入一些调用延迟或者服务降级的容错机制。

    Hystrix的设计原则

    • 对依赖服务调用时出现的调用延迟和调用失败进行控制和容错保护
    • 在复杂的分布式系统中,阻止某一个依赖服务的故障在整个系统中蔓延
    • 提供fail-fast(快速失败)和快速恢复的支持
    • 提供fallback优雅降级的支持
    • 支持近实时的监控、报警以及运维操作

    编写Hystrix类

    import (
        "errors"
        "github.com/afex/hystrix-go/hystrix"
        "sync"
    )
    
    var config = hystrix.CommandConfig{
        Timeout:                5000, //执行command的超时时间(毫秒)
        MaxConcurrentRequests:  8,    //command的最大并发量
        SleepWindow:            1000, //过多长时间,熔断器再次检测是否开启。单位毫秒
        ErrorPercentThreshold:  30,   //错误率 请求数量大于等于RequestVolumeThreshold并且错误率到达这个百分比后就会启动
        RequestVolumeThreshold: 5,    //请求阈值(一个统计窗口10秒内请求数量)  熔断器是否打开首先要满足这个条件;这里的设置表示至少有5个请求才进行ErrorPercentThreshold错误百分比计算
    }
    
    type runFunc func() error
    
    type Hystrix struct {
        loadMap  *sync.Map //储存每个调用函数对应的 Hystrix
        fallback string   //降级信息
    }
    
    func NewHystrix(msg string) *Hystrix {
        return &Hystrix{
            loadMap:  new(sync.Map),
            fallback: msg,
        }
    }
    
    func (s *Hystrix) Run(name string, run runFunc) error {
        if _, ok := s.loadMap.Load(name); !ok {
            hystrix.ConfigureCommand(name, config)
            s.loadMap.Store(name, name)
        }
        //name 为执行的命令名称
        //run  我们要执行的函数
        //fallback:run运行过程中发生错误时的回调方法
        err := hystrix.Do(name, func() error {
            return run()
        }, func(err error) error {
            //fmt.Println("运行 run 方法错误", err)
            return errors.New(s.fallback)
        })
        if err != nil {
            return err
        }
        return nil
    }
    

    添加Hystrix到调用客户端

    • 这里为了展示Hystrix的状态去掉了一些日志信息
    hy := utils.NewHystrix("调用错误服务降级")
    cbs, _, _ := hystrix.GetCircuit("login")
    for i := 0; i < 100; i++ {
        time.Sleep(time.Millisecond * 100)
        userAgent, err := client.UserAgentClient()
        if err != nil {
            t.Error(err)
            return
        }
    err = hy.Run("login", func() error {
        _, err := userAgent.Login(context.Background(), &pb.Login{
            Account:  "hwholiday",
            Password: "123456",
        })
        if err != nil {
            return err
        }
            //fmt.Println(ack.Token)
            return nil
        })
    fmt.Println("熔断器开启状态:", cbs.IsOpen(), "请求是否允许:", cbs.AllowRequest())
        if err != nil {
            t.Log(err)
        }
    }
    

    去掉服务端的请求限制功能

    func NewEndPointServer(svc Service, limit *rate.Limiter) EndPointServer {
        var loginEndPoint endpoint.Endpoint
        {
            loginEndPoint = MakeLoginEndPoint(svc)
            //loginEndPoint = NewGolangRateAllowMiddleware(limit)(loginEndPoint)
        }
        return EndPointServer{LoginEndPoint: loginEndPoint}
    }
    

    模拟服务器错误功能

    if in.Account != "hwholiday" || in.Password != "123456" {
        err = errors.New("用户信息错误")
        return
    }
    //模拟耗时
    //rand.Seed(time.Now().UnixNano())
    //sl := rand.Int31n(10-1) + 1
    //time.Sleep(time.Duration(sl) * time.Millisecond * 100)
    //模拟错误
    if rand.Intn(10) > 3 {
        err = errors.New("服务器运行错误")
        return
    }
    ack = &pb.LoginAck{}
    

    运行

    • 运行 TestNewUserAgentClient 方法 (调用Login接口100次)

       

    熔断器开启状态: true 请求是否允许: false
    熔断器开启状态: true 请求是否允许: false
    s.LoginEndPoint rpc error: code = Unknown desc = 服务器运行错误
    s.LoginEndPoint rpc error: code = Unknown desc = 服务器运行错误
    s.LoginEndPoint rpc error: code = Unknown desc = 服务器运行错误
    s.LoginEndPoint rpc error: code = Unknown desc = 服务器运行错误 (previously: rpc error: code = Unknown desc = 服务器运行错误; rpc error: code = Unknown desc = 服务器运行错误)
    熔断器开启状态: true 请求是否允许: false
    熔断器开启状态: true 请求是否允许: false
    熔断器开启状态: true 请求是否允许: false
    熔断器开启状态: true 请求是否允许: false
    熔断器开启状态: true 请求是否允许: false
    熔断器开启状态: true 请求是否允许: false
    熔断器开启状态: true 请求是否允许: false
    熔断器开启状态: true 请求是否允许: false
    熔断器开启状态: true 请求是否允许: false
    熔断器开启状态: true 请求是否允许: false
    熔断器开启状态: false 请求是否允许: true
    s.LoginEndPoint rpc error: code = Unknown desc = 服务器运行错误
    熔断器开启状态: false 请求是否允许: true

    
    ## 结语
    + 我们可以看到Hystrix的状态从 打开 ->关闭 -> 打开
    + Hystrix的用法还有很多,这里只展示简单的使用,更加高级的功能欢迎大家一起讨论
    + 欢迎添加QQ一起讨论
    
    
    ### [完整代码地址](https://github.com/hwholiday/learning_tools/tree/master/go-kit/v8)


    作者:hwholiday
    链接:https://www.jianshu.com/p/15975197c2be
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    GO语言面向对象06---面向对象练习01
    GO语言面向对象05---接口的多态
    GO语言面向对象04---接口的继承
    GO语言面向对象03---接口与断言
    GO语言面向对象02---继承
    Go语言练习---判断闰年以及根据现在的秒数求现在的年月日
    [操作系统] 线程管理
    [操作系统] 进程的状态
    [操作系统] 进程控制块
    关于这次计算机设计大赛
  • 原文地址:https://www.cnblogs.com/ExMan/p/12653835.html
Copyright © 2011-2022 走看看