3、限流算法基础:漏桶算法原理与适用场景

漏桶算法(Leaky Bucket)是限流领域最经典的算法之一,其核心思想是将突发流量“削峰填谷”,以恒定速率处理请求。在自愈剧本的 Runbook 验证中,漏桶常用于保护下游脆弱服务,防止流量尖峰击穿系统。

3.1 算法原理

漏桶算法将系统抽象为一个底部有孔的固定容量水桶:

  • 桶容量(Capacity):桶的最大容量,对应系统允许的最大突发请求数。
  • 漏水速率(Leak Rate):桶底部孔洞的流出速率,对应系统恒定的处理速率。
  • 流入请求(Incoming Requests):任意速率的水流注入桶中。
  • 溢出丢弃(Overflow Drop):当桶满时,新注入的水(请求)直接溢出丢弃。

无论外部请求如何突发,漏桶始终以固定的漏水速率向下游转发请求,从而实现对后端服务的平滑保护。

关键公式: 当前桶中水量 = min(桶容量, 上次水量 + 新请求数 - 漏水速率 × 时间间隔)

3.2 漏桶算法工作流程

  1. 请求到达:新请求进入系统,检查当前桶中水量。
  2. 容量判断:若桶中水量 + 1 ≤ 桶容量,则请求入桶;否则请求被丢弃(限流)。
  3. 恒定漏水:系统以固定速率从桶中取出请求进行处理。
  4. 处理完成:请求被下游服务消费,桶中水量减少。
漏桶算法核心原理图 漏桶算法核心原理图 突发请求 流入 漏桶(容量 C) 当前水量 = 待处理请求 孔洞 恒定速率漏水 恒定处理 溢出丢弃 桶满时溢出

3.3 漏桶 vs 令牌桶:核心差异

对比维度 漏桶算法 令牌桶算法
输出速率 严格恒定,完全平滑 允许短时突发,平均速率受限
应对突发 突发请求被缓存或丢弃 允许一定程度的突发消费
实现复杂度 低,只需维护水量和计时器 中,需维护令牌生成和桶状态
适用场景 下游处理能力固定的场景 允许短时突发的业务场景
内存开销 O(1),仅记录桶状态 O(1),仅记录令牌数

3.4 适用场景分析

漏桶算法在以下场景中表现优异:

  • 数据库连接池保护:数据库连接数有限,漏桶确保每秒查询数恒定,防止连接风暴。
  • 第三方 API 调用:外部 API 通常有严格的 QPS 限制,漏桶可确保调用速率不超标。
  • 消息队列消费:消费者处理能力固定,漏桶可平滑生产者突发消息。
  • 硬件设备控制:如打印机、传感器等物理设备,处理速率固定,漏桶天然匹配。
自愈剧本提示: 在 Runbook 验证中,漏桶常用于“下游保护”步骤。当检测到下游服务延迟升高时,自愈剧本可动态降低漏桶的漏水速率,实现自适应限流。

3.5 漏桶算法实现示例

// 漏桶限流器(Go 语言示例)
type LeakyBucket struct {
    capacity   int           // 桶容量
    leakRate   int           // 每秒漏水速率
    water      int           // 当前水量
    lastLeakMs int64         // 上次漏水时间戳(毫秒)
    mu         sync.Mutex
}

func (lb *LeakyBucket) Allow() bool {
    lb.mu.Lock()
    defer lb.mu.Unlock()

    now := time.Now().UnixMilli()
    // 计算时间间隔内应漏掉的水量
    elapsed := now - lb.lastLeakMs
    leaked := int(elapsed) * lb.leakRate / 1000

    if leaked > 0 {
        lb.water -= leaked
        if lb.water < 0 {
            lb.water = 0
        }
        lb.lastLeakMs = now
    }

    // 判断是否允许请求
    if lb.water < lb.capacity {
        lb.water++
        return true
    }
    return false // 桶满,丢弃请求
}

3.6 漏桶算法的局限性

注意: 漏桶算法不适合需要应对突发流量的业务场景。例如电商秒杀、热点新闻推送等场景,漏桶会强制削平所有突发,导致用户体验下降。此时应优先考虑令牌桶或滑动窗口算法。
  • 缺乏弹性:即使下游有能力处理更多请求,漏桶也不会加速。
  • 响应延迟:突发请求在桶中排队,可能增加平均响应时间。
  • 参数敏感:桶容量和漏水速率需要精确配置,否则容易过度限流或保护不足。
漏桶算法适用场景决策树 漏桶算法适用场景决策树 下游处理能力是否固定? 是 推荐使用漏桶算法 否 考虑令牌桶/滑动窗口 典型场景 数据库连接池 第三方 API 调用 消息队列消费 硬件设备控制 决策要点:若下游服务无法处理突发流量,且需要严格恒定输出, 则漏桶算法是最优选择;否则应选用更灵活的限流算法。

3.7 自愈剧本中的漏桶实践

在 Runbook 验证案例中,漏桶算法通常作为“限流保护”步骤的核心组件:

自愈阶段 漏桶角色 验证要点
故障检测 监控桶溢出率(丢弃请求数) 溢出率突增是否触发告警
限流执行 动态调整漏水速率 速率调整后下游负载是否稳定
恢复验证 恢复默认桶参数 恢复正常后请求是否不再被丢弃
Runbook 验证指标: 漏桶算法在自愈剧本中的关键验证指标包括:
• 桶溢出率(Overflow Rate)
• 平均排队延迟(Average Queue Delay)
• 下游服务 P99 响应时间
• 限流触发次数与恢复时间