Golang标准库限流器rate使用

       限流就是限制系统的输入和输出流量来达到保护系统的目的,限流在实际场景中应用十分广泛,尤其在高并发场景下,为了保证系统的可以用性,我们需要采取一些限流措施降级,一旦达到限制的阈值,就需要限制流量并采取一些措施来完成限制流量的目的(比如:延迟处理、拒绝处理等),以防止过多的请求而导致系统崩溃。

在golang的标准库golang.org/x/time/rate有一个限流器的实现,这个限流器的实现方案是令牌桶。

 

1、令牌桶

令牌桶是比较常见的限流算法之一,如下图所示:

        令牌桶可以用来限制突发的流量,在下面图中,有一个桶,桶的大小是固定的,系统以一定的速率往桶中添加令牌,当桶满时,就会溢出,新添加的令牌会被丢弃。当请求需要被处理时,需要先从桶中获取令牌,当没有令牌可取时,则可以选择排队等待或者拒绝服务。

在这里插入图片描述

从上面的图看来,令牌桶的实现需要一个定时器和等待队列,定时器以一定的频率往桶中放入令牌,而等待队列用于存放等待的请求。但是这样的实现效率太低,在golang的标准库中的实现是通过计算时间的差值来算出令牌的。

 

2、标准库限流器的使用

标准库中的限流器相关定义如下:

Limit:速率,定义了某些事件的最大速率,为每秒事件数,也就是每秒往令牌桶中放入多少个令牌。Inf是无限速率。

type Limit float64

const Inf = Limit(math.MaxFloat64)

Every:这个函数可以将产生一个令牌的时间转化为每秒产生多少个令牌,比如100ms产生一个令牌,那么1s将产生10个令牌。

func Every(interval time.Duration) Limit {
   
   
	if interval <= 0 {
   
   
		return Inf
	}
	return 1 / Limit(interval.Seconds())
}

NewLimiter:创建一个限流器

func NewLimiter(r Limit, b int) *Limiter {
   
   
	return &Limiter{
   
   
		limit: r,
		burst: b,
	}
}

参数如下:

  • 第一个参数r Limit:产生令牌的速率,也就是每秒往桶中放入多少个令牌。
  • 第二个参数b int:令牌桶的大小。

对于下面这个例子,就是构造一个每秒产生10个令牌,令牌桶大小为20的限流器:

limiter := NewLimiter(10, 20)

 

2.1 消费令牌

Limiter提供了三种消费令牌的方法,可以用来消费一个或多个令牌,每种方法代表了当令牌不足时,各种的对应手段:

  • Wait / WaitN
  • Allow / AllowN
  • Reserve / ReserveN

 

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)

WaitN消费n个令牌,如果令牌的数量不够,将会阻塞等待。它的第一个参数为Context,也就是我们可以控制等待的最大时长。如果n超过了突发大小也就是桶的大小、Context被取消或者预期的等待时间超过了Context的Deadline,将会返回一个错误。

 

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

Allow相当于AllowN(time.Now(), 1)

AllowN可以用来获取截至到某一时间,是否有n个令牌可用。如果满足则返回true,同时消费n个令牌,反之则不消费,返回false。

通常用于不满足条件则直接丢弃请求。

 

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

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

ReserveN返回一个Reservation,Reservation可用用来指示在有n个令牌可用之前必须等待多长时间。

可用调用Reservation的Delay方法来获取需要等待的时间:

func (r *Reservation) Delay() time.Duration

或者调用Cancel来取消,该方法会将token归还:

func (r *Reservation) Cancel()

ReserveN的使用示例如下:

r := lim.ReserveN(time.Now(), 1)
if !r.OK() 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值