美文网首页
go-kit 微服务 限流 (uber/ratelimit 和

go-kit 微服务 限流 (uber/ratelimit 和

作者: hwholiday | 来源:发表于2020-01-10 14:42 被阅读0次

    golang/rate 简介(golang.org/x/time/rate)

    • golang 标准库中就自带的限流算法
    • 该限流器是基于 Token Bucket(令牌桶) 实现的
    //第一个参数是 r Limit。代表每秒可以向 Token 桶中产生多少 token
    //第二个参数是 b int。b 代表 Token 桶的容量大小
    golangLimit := rate.NewLimiter(10, 1)
    //golangLimit 其令牌桶大小为 1, 以每秒 10 个 Token 的速率向桶中放置 Token。
    
    
    • Wait/WaitN
      • Wait 实际上就是 WaitN(ctx,1)
      • 当使用 Wait 方法时,如果令牌桶内Token(大于or等于 N)直接返回,如果当时令牌桶内 Token 不足(小于 N),那么 Wait 方法将会阻塞,直到能从令牌桶内获得 Token
    • Allow/AllowN
      • Allow 实际上就是 AllowN(time.Now(),1)。
      • 当使用使用 AllowN 方法时,截止到time.Now()这一时刻(time可以自己传入)令牌桶中数目必须(大于or等于 N),满足则返回正确,同时从令牌桶中消费 N 个 Token
      • 应用场景请求速度太快就直接丢掉一些请求
    • Reserve/ReserveN
      • Reserve 相当于 ReserveN(time.Now(), 1)
      • 当使用使用 ReserveN 方法时,不管能不能从令牌桶内获取到Token都会返回一个Reservation对象
      • Reservation对象的 Ok() 方法返回了令牌桶是否可以在最大等待时间内提供请求的令牌数量,如果OK为false,则Delay()返回InfDuration
      • Reservation对象的 Delay() 方法返回了需要等待的时间,如果时间为0则不需要等待
      • 如果不想等待就调用 Reservation对象的 Cancel()

    uber/ratelimit 简介(go.uber.org/ratelimit)

    • uber 开源的限流算法,
    • 该组件基于 Leaky Bucket(漏桶) 实现的
    //一秒请求一次
    uberLimit := ratelimit.New(1)         
    //使用方法
    uberLimit.Take()        
    

    Endpoint层修改

    • 添加基于golang.org/x/time/rate的限流中间件
    func NewGolangRateAllowMiddleware(limit *rate.Limiter) endpoint.Middleware {
        return func(next endpoint.Endpoint) endpoint.Endpoint {
            return func(ctx context.Context, request interface{}) (response interface{}, err error) {
                if !limit.Allow() {
                    return "", errors.New("limit req  Allow")
                }
                return next(ctx, request)
            }
        }
    }
    
    
    • 添加基于go.uber.org/ratelimit的限流中间件
    func NewUberRateMiddleware(limit ratelimit.Limiter) endpoint.Middleware {
        return func(next endpoint.Endpoint) endpoint.Endpoint {
            return func(ctx context.Context, request interface{}) (response interface{}, err error) {
                limit.Take()
                return next(ctx, request)
            }
        }
    }
    
    • 对于需要限流的方法添加限流中间件
    func NewEndPointServer(svc v4_service.Service, log *zap.Logger, limit *rate.Limiter, limiter ratelimit.Limiter) EndPointServer {
        var addEndPoint endpoint.Endpoint
        {
            addEndPoint = MakeAddEndPoint(svc)
            addEndPoint = LoggingMiddleware(log)(addEndPoint)
            addEndPoint = AuthMiddleware(log)(addEndPoint)
            addEndPoint = NewUberRateMiddleware(limiter)(addEndPoint)
        }
        var loginEndPoint endpoint.Endpoint
        {
            loginEndPoint = MakeLoginEndPoint(svc)
            loginEndPoint = LoggingMiddleware(log)(loginEndPoint)
            loginEndPoint = NewGolangRateAllowMiddleware(limit)(loginEndPoint)
        }
        return EndPointServer{AddEndPoint: addEndPoint, LoginEndPoint: loginEndPoint}
    }
    

    激动人心的时刻来了,修改main方法

    utils.NewLoggerServer()
    golangLimit := rate.NewLimiter(10, 1) //每秒产生10个令牌,令牌桶的可以装1个令牌
    uberLimit := ratelimit.New(1)         //一秒请求一次
    server := v4_service.NewService(utils.GetLogger())
    endpoints := v4_endpoint.NewEndPointServer(server, utils.GetLogger(), golangLimit, uberLimit)
    httpHandler := v4_transport.NewHttpHandler(endpoints, utils.GetLogger())
    utils.GetLogger().Info("server run 0.0.0.0:8888")
    _ = http.ListenAndServe("0.0.0.0:8888", httpHandler))
    

    日志(一秒请求100次接口)

    • 日志比较多这里我减少了一些日志以便于观看

    • go.uber.org/ratelimit的限流中间件

    2020-01-03 09:46:30     DEBUG   v4_transport/transport.go:70    5fd6eae3-32ea-5a24-9507-ed3c865f2e50    {" 开始解析请求数据": {"a":1,"b":1}}
    2020-01-03 09:46:31     DEBUG   v4_transport/transport.go:70    ca39186b-c4e1-5976-bb02-f5e484aeca48    {" 开始解析请求数据": {"a":1,"b":1}}
    2020-01-03 09:46:32     DEBUG   v4_transport/transport.go:70    691bfdf1-6701-553f-ae78-d443eff6fb6b    {" 开始解析请求数据": {"a":1,"b":1}}
    ......
    可以看到请求是按照我们控制的一秒一秒请求的
    
    • golang.org/x/time/rate的限流中间件
    2020-01-03 09:42:17     DEBUG   v4_transport/transport.go:75    cc74b82d-4fa9-558c-acd3-ad2ea292dfdd    {"请求结束封装返回值":"token"}}
    2020-01-03 09:42:17     WARN    v4_transport/transport.go:20    c1a00c56-edad-55b0-b546-076a0d070086    {"error": "limit req  Allow"}
    2020-01-03 09:42:17     DEBUG   v4_transport/transport.go:75    2c8ab986-c300-5df1-99fc-0d88c8db8c40    {"请求结束封装返回值":"token"}}
    2020-01-03 09:42:17     WARN    v4_transport/transport.go:20    8e5dc5d4-e048-56c7-9a42-33863843cd67    {"error": "limit req  Allow"}
    ......
    

    结语

    • 在请求数量过多且我们的服务处理不完时,添加限流能保证我们服务的健康状态
    • 在文章中我只展示了下限流在go-kit里面的简单使用
    • 欢迎添加QQ一起讨论

    完整代码地址

    联系 QQ: 3355168235

    相关文章

      网友评论

          本文标题:go-kit 微服务 限流 (uber/ratelimit 和

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