固定窗口又称固定窗口(又称计数器算法)
是最简单的限流算法,通过在单位时间内维护的计数器来控制该时间单位内的最大访问量,
易于实现;并且内存占用小,我们只需要存储时间窗口中的计数即可;它能够确保处理更多的最新请求,不会因为旧请求的堆积导致新请求被饿死。当然也面临着临界问题,当两个窗口交界处,瞬时流量可能为2n
package main
import (
"sync"
"time"
)
type LimitRate struct {
rate int // 阀值
begin time.Time // 计数开始时间
cycle time.Duration // 计数周期
count int // 收到的请求数
lock sync.Mutex // 锁
}
func (limit *LimitRate) Allow() bool {
limit.lock.Lock()
defer limit.lock.Unlock()
// 判断收到请求数是否达到阀值
if limit.count == limit.rate-1 {
now := time.Now()
// 达到阀值后,判断是否是请求周期内
if now.Sub(limit.begin) >= limit.cycle {
limit.Reset(now)
return true
}
return false
} else {
limit.count++
return true
}
}
func (limit *LimitRate) Reset(begin time.Time) {
limit.begin = begin
limit.count = 0
}
滑动窗口
为了防止瞬时流量,可以把固定窗口近一步划分成多个格子,每次向后移动一小格,而不是固定窗口大小,这就是滑动窗口(Sliding Window)。
package main
import (
"container/list"
"fmt"
"sync"
"time"
)
func main() {
for {
time.Sleep(1 * time.Second)
a := limit(time.Now().Unix())
fmt.Println(a)
}
}
var timeWindow int64 = 2
var lock sync.Mutex
var link = list.New()
func limit(nowTime int64) bool {
lock.Lock()
defer lock.Unlock()
if link.Len() < 5 {
link.PushBack(nowTime)
return true
} else {
//判断最右一个
if nowTime-link.Back().Value.(int64) > timeWindow {
link.PushBack(nowTime)
//删除
link.Remove(link.Front())
return true
} else {
return false
}
}
}
漏桶算法
请求被放在桶里,不会被丢弃,以恒定速度处理,流出 类似消息队列
令牌桶算法
请求去拿流量,突发