Go官方的限流器 time/rate 如何使用

幸运草 2020年4月12日21:43:53前端框架评论阅读模式
本主题为系列文章,分上下两篇。本文主要介绍time/rate的具体使用方法,下一篇文章将会着重介绍其内部实现原理。

限流器是后台服务中的非常重要的组件,可以用来限制请求速率,保护服务,以免服务过载。限流器的实现方法有很多种,例如滑动窗口法、Token Bucket、Leaky Bucket等。

其实golang标准库中就自带了限流算法的实现,即golang.org/x/time/rate。该限流器是基于Token Bucket(令牌桶)实现的。

简单来说,令牌桶就是想象有一个固定大小的桶,系统会以恒定速率向桶中放Token,桶满则暂时不放。而用户则从桶中取Token,如果有剩余Token就可以一直取。如果没有剩余Token,则需要等到系统中被放置了Token才行。

本文则主要集中介绍下该组件的具体使用方法:

构造一个限流器

我们可以使用以下方法构造一个限流器对象:

limiter := NewLimiter(10, 1);

这里有两个参数:

  1. 第一个参数是r Limit。代表每秒可以向Token桶中产生多少token。Limit实际上是float64的别名。
  2. 第二个参数是b int。b代表Token桶的容量大小。

那么,对于以上例子来说,其构造出的限流器含义为,其令牌桶大小为1, 以每秒10个Token的速率向桶中放置Token。

除了直接指定每秒产生的Token个数外,还可以用Every方法来指定向Token桶中放置Token的间隔,例如:

limit := Every(100 * time.Millisecond);limiter := NewLimiter(limit, 1);

以上就表示每100ms往桶中放一个Token。本质上也就是一秒钟产生10个。

Limiter提供了三类方法供用户消费Token,用户可以每次消费一个Token,也可以一次性消费多个Token。而每种方法代表了当Token不足时,各自不同的对应手段。

Wait/WaitN

func (lim *Limiter) Wait(ctx context.Context) (err error)func (lim *Limiter) WaitN(ctx context.Context, n int) (err error)

Wait实际上就是WaitN(ctx,1)。

当使用Wait方法消费Token时,如果此时桶内Token数组不足(小于N),那么Wait方法将会阻塞一段时间,直至Token满足条件。如果充足则直接返回。

这里可以看到,Wait方法有一个context参数。我们可以设置context的Deadline或者Timeout,来决定此次Wait的最长时间。

Allow/AllowN

func (lim *Limiter) Allow() boolfunc (lim *Limiter) AllowN(now time.Time, n int) bool

Allow实际上就是AllowN(time.Now(),1)。

AllowN方法表示,截止到某一时刻,目前桶中数目是否至少为n个,满足则返回true,同时从桶中消费n个token。反之返回不消费Token,false。

通常对应这样的线上场景,如果请求速率过快,就直接丢到某些请求。

Reserve/ReserveN

func (lim *Limiter) Reserve() *Reservationfunc (lim *Limiter) ReserveN(now time.Time, n int) *Reservation

Reserve相当于ReserveN(time.Now(), 1)。

ReserveN的用法就相对来说复杂一些,当调用完成后,无论Token是否充足,都会返回一个Reservation*对象。

你可以调用该对象的Delay()方法,该方法返回了需要等待的时间。如果等待时间为0,则说明不用等待。必须等到等待时间之后,才能进行接下来的工作。

或者,如果不想等待,可以调用Cancel()方法,该方法会将Token归还。

举一个简单的例子,我们可以这么使用Reserve方法。

r := lim.Reserve()f !r.OK() {    // Not allowed to act! Did you remember to set lim.burst to be > 0 ?    return}time.Sleep(r.Delay())Act() // 执行相关逻辑

动态调整速率

Limiter支持可以调整速率和桶大小:

  1. SetLimit(Limit) 改变放入Token的速率
  2. SetBurst(int) 改变Token桶大小

有了这两个方法,可以根据现有环境和条件,根据我们的需求,动态的改变Token桶大小和速率。

特别声明:以上文章内容仅代表作者本人观点,不代表变化吧观点或立场。如有关于作品内容、版权或其它问题请于作品发表后的30日内与变化吧联系。

  • 赞助本站
  • 微信扫一扫
  • weinxin
  • 加入Q群
  • QQ扫一扫
  • weinxin
幸运草
Go语言接口规则 前端框架

Go语言接口规则

Go语言接口规则 接口是一个或多个方法签名的集合。任何类型的方法集中只要拥有该接口对应的全部方法签名。就表示它 "实现" 了该接口,无须在该类型上显式声明实现了哪个接口。对应方法,是指有相同名称、参数...
Go语言中处理 HTTP 服务器 前端框架

Go语言中处理 HTTP 服务器

1 概述 包 net/http 提供了HTTP服务器端和客户端的实现。本文说明关于服务器端的部分。 快速开始: package main import (   "log"   "net/http" )...

发表评论