源码地址:golang.org/x/time/rate
rate包是Google基于令牌桶的算法实现的限流器,可以在服务的限流中使用。
一、数据结构
1.常量变量
//定义某个时间的最大频率
//表示每秒的事件数
type Limit float64
//Inf表示无速率限制
const Inf = Limit(math.MaxFloat64)
2. 结构体
Limiter结构体
type Limiter struct {
limit Limit //每秒允许处理的事件数量,即每秒处理事件的频率
burst int //令牌桶的最大数量, 如果burst为0,则除非limit == Inf,否则不允许处理任何事件。
mu sync.Mutex
tokens float64 //令牌桶中可用的令牌数量
// last is the last time the limiter's tokens field was updated
//记录上次limiter的tokens被更新的时间
last time.Time
// lastEvent is the latest time of a rate-limited event (past or future)
//lastEvent记录速率受限制(桶中没有令牌)的时间点,该时间点可能是过去的,也可能是将来的(Reservation预定的结束时间点)
lastEvent time.Time
}
Limiter是限流器中最核心的结构体,用于限流(控制事件发生的频率),在初始化后默认是满的,并以每秒r个令牌的速率重新填充直到达到桶的容量(burst),如果r == Inf表示无限制速率。
Limiter有三个主要的方法 Allow、Reserve和Wait,最常用的是Wait和Allow方法
这三个方法每调用一次都会消耗一个令牌,这三个方法的区别在于没有令牌时,他们的处理方式不同
Allow: 如果没有令牌,则直接返回false
Reserve:如果没有令牌,则返回一个reservation,
Wait:如果没有令牌,则等待直到获取一个令牌或者其上下文被取消。
tokens更新的策略:
1). 成功获取到令牌或成功预约(Reserve)到令牌
2). 预约取消时(Cancel)并且需要还原令牌到令牌桶中时
3). 重新设置限流器的速率时(SetLimit)
4. 重新设置限流器的容量时(SetBurst)
lastEvent表示速率受限制的时间点,它可能时过去的时间,也可能时将来的时间。
如果没有预约令牌的话,该时间等于last,是过去的
如果有预约令牌的话,该时间等于最新的预约的截至时间。
注意:由于令牌桶的令牌可以预约,所有令牌桶中的tokens可能为负数。
Reservation结构体
type Reservation struct {
ok bool //到截至时间是否可以获取足够的令牌
lim *Limiter
tokens int //需要获取的令牌数量
timeToAct time.Time //需要等待的时间点
// This is the Limit at reservation time, it can change later.
limit Limit
}
Reservation可以理解成预定令牌的操作,timeToAct是本次预约需要等待到的指定时间点才有足够预约的令牌。