gocookbook
gocookbook copied to clipboard
限流算法--漏桶算法
算法思想
与令牌桶是“反向”的算法,当有请求到来时先放到木桶中,worker以固定的速度从木桶中取出请求进行相应。如果木桶已经满了,直接返回请求频率超限的错误码或者页面。
适用场景
流量最均匀的限流方式,一般用于流量“整形”,例如保护数据库的限流。先把对数据库的访问加入到木桶中,worker再以db能够承受的qps从木桶中取出请求,去访问数据库。不太适合电商抢购和微博出现热点事件等场景的限流。
go语言实现
// 漏桶
// 一个固定大小的桶,请求按照固定的速率流出
// 如果桶是空的,不需要流出请求
// 请求数大于桶的容量,则抛弃多余请求
type LeakyBucket struct {
rate float64 // 每秒固定流出速率
capacity float64 // 桶的容量
water float64 // 当前桶中请求量
lastLeakMs int64 // 桶上次漏水微秒数
lock sync.Mutex // 锁
}
func (leaky *LeakyBucket) Allow() bool {
leaky.lock.Lock()
defer leaky.lock.Unlock()
now := time.Now().UnixNano() / 1e6
// 计算剩余水量,两次执行时间中需要漏掉的水
leakyWater := leaky.water - (float64(now-leaky.lastLeakMs) * leaky.rate / 1000)
leaky.water = math.Max(0, leakyWater)
leaky.lastLeakMs = now
if leaky.water+1 <= leaky.capacity {
leaky.water++
return true
} else {
return false
}
}
func (leaky *LeakyBucket) Set(rate, capacity float64) {
leaky.rate = rate
leaky.capacity = capacity
leaky.water = 0
leaky.lastLeakMs = time.Now().UnixNano() / 1e6
}