漏桶算法可以看作是一个强制限制输出速率的模式。无论输入请求多么猛烈,输出(处理)速率始终是恒定的。
工作原理
逻辑图解
突发流量 (流入速度不限)
↓ ↓ ↓
+-----------+
| \ / |
| \____/ | ← 漏桶容量 B
| (Requests)|
+-----------+
↓ ↓ ↓
恒定流出速率 R (处理请求)- 注入请求:所有的请求进入系统时就像水滴进入漏桶。
- 漏桶容量:桶有固定容量。如果请求进入的速率太快,导致桶满了,新进入的请求会被直接丢弃。
- 恒定流出:漏桶底部的“漏洞”以恒定的速率(如每秒 个)往外流水(处理请求)。
Go 语言实现 (示例)
type LeakyBucket struct {
capacity float64 // 桶容量 B
rate float64 // 处理速率 R (个/秒)
water float64 // 当前桶中的请求数 (积水)
lastTime time.Time // 上次漏水时间
mu sync.Mutex
}
func (b *LeakyBucket) Allow() bool {
b.mu.Lock()
defer b.mu.Unlock()
now := time.Now()
// 1. 根据经过的时间计算流出的请求数 (漏水)
passedTime := now.Sub(b.lastTime).Seconds()
leakedWater := passedTime * b.rate
b.water -= leakedWater
if b.water < 0 {
b.water = 0
}
b.lastTime = now
// 2. 判断桶是否已满
if b.water < b.capacity {
b.water++
return true
}
return false
}核心特点
- 强制平滑:它将突发的流量转化为平滑的恒定流量。
- 不允许突发:即便桶里有空位,流出的速度也永远不会超过 。这与令牌桶有本质区别。
- 系统保护效果极佳:由于处理速度恒定,系统压力非常可预测。
应用场景
- 网络流量控制:经典的异步处理场景,不管上游有多少并发,下游处理器的压力始终如一。
- 数据库保护:防止瞬时高峰流量直接打垮数据库。