漏桶算法可以看作是一个强制限制输出速率的模式。无论输入请求多么猛烈,输出(处理)速率始终是恒定的。

工作原理

逻辑图解

    突发流量 (流入速度不限)
       ↓  ↓  ↓
    +-----------+
    | \      /  |
    |  \____/   | ← 漏桶容量 B
    | (Requests)|
    +-----------+
       ↓  ↓  ↓
      恒定流出速率 R (处理请求)
  1. 注入请求:所有的请求进入系统时就像水滴进入漏桶。
  2. 漏桶容量:桶有固定容量。如果请求进入的速率太快,导致桶满了,新进入的请求会被直接丢弃。
  3. 恒定流出:漏桶底部的“漏洞”以恒定的速率(如每秒 个)往外流水(处理请求)。

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
}

核心特点

  • 强制平滑:它将突发的流量转化为平滑的恒定流量。
  • 不允许突发:即便桶里有空位,流出的速度也永远不会超过 。这与令牌桶有本质区别。
  • 系统保护效果极佳:由于处理速度恒定,系统压力非常可预测。

应用场景

  • 网络流量控制:经典的异步处理场景,不管上游有多少并发,下游处理器的压力始终如一。
  • 数据库保护:防止瞬时高峰流量直接打垮数据库。