漏桶和令牌桶有啥区别?

#中间件#面试八股

漏桶和令牌桶有啥区别?

结论:漏桶(Leaky Bucket)以恒定速率放行,把突发流量整形为均匀流量;令牌桶(Token Bucket)以恒定速率产生令牌,桶里攒下的令牌允许一次性突发。要削峰稳压用漏桶,要限平均速率又容许突发用令牌桶——绝大多数接口限流场景选令牌桶。

一、核心差异

维度漏桶令牌桶
桶里装什么待处理的请求可消耗的令牌
输出速率恒定平均恒定,瞬时可变
突发支持不支持,超出即排队或丢弃支持,受桶容量限制
容量含义可排队的请求数可一次性消耗的令牌数
典型实现队列加定时出队、Sentinel 匀速排队Guava RateLimiter、Redis 令牌桶 Lua
适用场景保护下游、流量整形接口限流、允许短时突发

二、两张图看懂

漏桶:不管进水多猛,出水口恒定          令牌桶:令牌匀速滴入,桶满则溢出
      ┌───────────┐                          ┌───────────┐
 请求 │  ┌─────┐  │ 恒定速率            令牌 │ ● ● ● ●   │
 ────►│  │ ███ │──┼──► 放行             ────►│ ● ● ●     │
 突发 │  │ ███ │  │                     生成 │ 容量上限  │
      │  └─────┘  │                          └─────┬─────┘
      └───────────┘                                │ 取到令牌才放行
        桶满则丢弃或排队                             ▼
                                              请求 ──► 放行

一个常被忽略的等价关系:漏桶的恒定输出,正是令牌桶在桶空时的行为;令牌桶多出来的只是「预存额度」。

三、代码:令牌桶(Guava)

// 每秒 100 个令牌,预热 3 秒:冷启动时逐步放开,避免瞬间打满
private final RateLimiter limiter =
        RateLimiter.create(100.0, 3, TimeUnit.SECONDS);

public boolean tryAcquire() {
    return limiter.tryAcquire();       // 非阻塞,拿不到立即返回 false
}

public void acquireBlocking() {
    limiter.acquire();                 // 阻塞直到拿到令牌
}

// 允许突发:SmoothBursty 默认 maxBurstSeconds = 1.0,
// 即桶容量约等于 1 秒的令牌量
RateLimiter bursty = RateLimiter.create(100.0);

Guava 的 SmoothBursty 是令牌桶,SmoothWarmingUp 是带预热的令牌桶;它没有现成的漏桶实现,需要自己用队列做。

四、代码:漏桶(Redis 队列加定时消费)

-- KEYS[1] = queue:api     ARGV[1] = 入队时间戳(ms)   ARGV[2] = 容量
-- 入队前检查排队长度,控制的是「队尾丢弃」
local len = redis.call('LLEN', KEYS[1])
if len >= tonumber(ARGV[2]) then
  return 0
end
redis.call('RPUSH', KEYS[1], ARGV[1])
return 1

消费端以固定间隔 LPOP 并转发,出队速率就是放行速率。Sentinel 的匀速排队(Rate Limiter)控制行为本质也是漏桶:请求按固定间隔排队通过,超过 maxQueueingTimeMs 直接拒绝。

五、常见追问

Q1:令牌桶能模拟漏桶吗? 不能完全等价。令牌桶在桶空时是恒定速率,但桶满时允许突发;把桶容量设为 1,就退化为「每 1/rate 秒放行一个」,接近漏桶,但缺少排队与平滑能力。

Q2:限流算法还有哪些? 固定窗口(最简单,有临界突刺)、滑动窗口(按时间片加权,精度高)、并发数限流(信号量,防慢调用堆积)、自适应限流(按 RT 与 CPU 动态调阈值)。

Q3:线上该选哪个? 对外 API 用令牌桶,允许用户短时突发,体验更好;保护脆弱下游(老数据库、第三方接口)用漏桶排队,让流量平滑;秒杀入口用滑动窗口加令牌桶组合。

Q4:桶容量怎么定? 容量决定能容忍多大的瞬时突发。经验值是「平均 QPS × 1 到 3 秒」;容量太大等于没限流,太小则用户点两下就被拒。

小结

  • 漏桶整形,令牌桶限速兼突发,区别在桶里装的是请求还是令牌。
  • 令牌桶是限流主力,漏桶适合保护下游与削峰。
  • 桶容量决定了能容忍多大突发,这个参数比速率更值得调。
笔记加载中…