限流器 由于业务应用系统的负载能力有限,为了防止非预期的请求对系统压力过大而拖垮业务应用系统。也就是面对大流量时,如何进行流量控制?服务接口的流量控制策略:分流、降级、限流等。本文讨论下限流策略,虽然降低了服务接口的访问频率和并发量,却换取服务接口和业务应用系统的高可用。 go自带的限流包 golang.org/x/time/rate 限流器定义: ~~~ type Limiter struct ~~~ Limter限制时间的发生频率,采用令牌池的算法实现。这个池子一开始容量为b,装满b个令牌,然后每秒往里面填充r个令牌。 由于令牌池中最多有b个令牌,所以一次最多只能允许b个事件发生,一个事件花费掉一个令牌。 创建一个限流器 ~~~ // NewLimiter returns a new Limiter that allows events up to rate r and permits // bursts of at most b tokens. func NewLimiter(r Limit, b int) *Limiter ~~~ 是否限流判断,true未达到流量上限,false已经达到流量上限 ~~~ // Allow is shorthand for AllowN(time.Now(), 1). func (lim *Limiter) Allow() bool // AllowN reports whether n events may happen at time now. // Use this method if you intend to drop / skip events that exceed the rate limit. // Otherwise use Reserve or Wait. func (lim *Limiter) AllowN(now time.Time, n int) bool ~~~ Allow 是函数 AllowN(time.Now(), 1)的简化函数。 AllowN标识在时间now的时候,n个事件是否可以同时发生(也意思就是now的时候是否可以从令牌池中取n个令牌)。如果你需要在事件超出频率的时候丢弃或跳过事件,就使用AllowN,否则使用Reserve或Wait. 如果希望根据频率限制等待和降低事件发生的速度而不丢掉事件,就使用这个方法。 我认为这里要表达的意思就是如果事件发生的频率是可以由调用者控制的话,可以用ReserveN 来控制事件发生的速度而不丢掉事件。如果要使用context的截止日期或cancel方法的话,使用WaitN。 ~~~ // Wait is shorthand for WaitN(ctx, 1). func (lim *Limiter) Wait(ctx context.Context) (err error) ~~~ ~~~ // WaitN blocks until lim permits n events to happen. // It returns an error if n exceeds the Limiter's burst size, the Context is // canceled, or the expected wait time exceeds the Context's Deadline. func (lim *Limiter) WaitN(ctx context.Context, n int) (err error) ~~~ Wait函数是阻塞的,会阻塞调用线程,使用时应当注意 Wait是WaitN(ctx, 1)的简化形式。 WaitN 阻塞当前直到lim允许n个事件的发生。 如果n超过了令牌池的容量大小则报错。 如果Context被取消了则报错。 如果lim的等待时间超过了Context的超时时间则报错。