go-rate库-限流

go-rate

https://pkg.go.dev/github.com/beefsack/go-rate#section-sourcefiles

用法

  • new():创建一个实例

  • wait():用来阻塞等待

  • try():返回两个值,一个是表示是否可以立刻执行,另一个是需要延迟多久执行

实现

它的实现是,任何一段时间interval内,不能有超过limit个请求

维护一个队列,队列头是最早的时间,队列元素不会删(相当于固定的token数),到了limit后就从头部移动到尾部

假如当前队列中数目不超过limit个(最一开始的情况)

后面的情况就是:每次对比下队列中最早的时间和当前时间,最早时间超过了当前时间说明已经被处理过了相当于有空闲token了,所以可以处理(设置时间,移动到队列尾),不用sleep;否则就sleep这个差值。

// Try returns true if under the rate limit, or false if over and the
// remaining time before the rate limit expires.
func (r *RateLimiter) Try() (ok bool, remaining time.Duration) {
    r.mtx.Lock()
    defer r.mtx.Unlock()
    now := time.Now()
    if l := r.times.Len(); l < r.limit {
        r.times.PushBack(now)
        return true, 0
    }
    frnt := r.times.Front()
    if diff := now.Sub(frnt.Value.(time.Time)); diff < r.interval {
        return false, r.interval - diff
    }
    frnt.Value = now
    r.times.MoveToBack(frnt)
    return true, 0
}

关键的操作是:if diff := now.Sub(frnt.Value.(time.Time)); diff < r.interval

走到这里队列是已经满了,必须挤掉一个人,且是挤掉最老的人,frnt是队列中最老的时间,所以当前时间和他相比,只要当前时间比最老的时间老且超过的时间小于r.interval - diff。

设计的含义是:r.interval这段时间内只能有r.limit个元素,队列长度最大就是r.limit;队列从头到尾时间是越来越新(大)。所以如果来一个新的请求,队列又满了,那么需要这个新请求的时间比最老的时间大且要大r.interval这么久,因为超过r.interval,这个最老的请求就可以移除了

aa

其他

它的处理不是时间片均匀的, 比如说设置1s有100个token,有100个线程来抢,cpu处理很快的话,可能0.1秒就处理完了剩下0.9秒都是闲的,这样的话CPU峰值会高但其他时间可能很闲。即CPU的工作不是很均匀。

增加分时间段不同的限流的功能

队列长度是动态变化的,不同的时间段,队列长度不同

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容