漏桶算法(Leaky Bucket)与 令牌桶算法(Token Bucket)

文章目录

  • 前言
  • 什么是漏桶算法(Leaky Bucket)?
    • ⛲ 漏桶核心特性
    • ⛲ 漏桶适用场景
  • 什么是令牌桶算法(Token Bucket)?
    • 令牌桶核心特性
    • 令牌桶适用场景
  • 漏桶 vs 令牌桶 对比总结
  • ️ Lua 限流应该用哪种?
  • 秒杀 Lua 令牌桶限流脚本示例
  • 小总结


前言

漏桶算法(Leaky Bucket)与 令牌桶算法(Token Bucket)


什么是漏桶算法(Leaky Bucket)?

  • 想象一个水桶,水滴(请求)不断滴入
  • 桶有一个小孔,水以固定速率流出
  • 超出桶容量的水滴(过多的请求)直接溢出,丢弃!

⛲ 漏桶核心特性

特性 解释
出水速率恒定 不管入水多快,出水速率固定,比如1秒100次
拒绝突发流量 桶满了就直接拒绝,不等待排队
整形输出 平滑请求流量,防止抖动、突刺

⛲ 漏桶适用场景

  • 限速处理器(防止系统流量抖动)
  • 保护下游服务(比如限 API 调用QPS)
  • 实时流处理(保证出口带宽平稳)

比如:

  • 每秒只允许100个请求,超出丢弃
  • API网关、CDN边缘节点,经常用漏桶!

什么是令牌桶算法(Token Bucket)?

  • 也是一个桶,但它装的是令牌(token)
  • 令牌以固定速率生成(比如每秒100个)
  • 每个请求必须拿到令牌才能继续,否则被限流
  • 桶可以存令牌,支持短时间突发流量

令牌桶核心特性

特性 解释
允许突发请求 桶里积累的令牌允许短时暴增请求
均匀填充令牌 按固定速率添加令牌,比如1秒100个
灵活速率 正常小流量可以慢慢用令牌,大流量爆发时快速消耗令牌

令牌桶适用场景

  • 秒杀/抢购系统(允许短时间内高并发冲击)
  • Web接口限流(允许短时间峰值爆发,但整体受控)
  • 防止用户体验卡顿(允许小范围高频请求)

比如:

  • 每秒生成100个令牌,积攒到桶容量500。
  • 突然来500个请求,也能快速放行,不会马上丢弃。

漏桶 vs 令牌桶 对比总结

比较维度 漏桶算法 令牌桶算法
出口流量 恒定速率,超限丢弃 灵活突发,令牌够可以爆发
突发流量处理能力 ❌ 不允许 ✅ 允许短时突发
实现复杂度 简单 稍复杂
应用场景 带宽整形、严格限速 秒杀、抢购、高并发接口

️ Lua 限流应该用哪种?

✅ 在秒杀、抢购、接口突发流量场景,
✅ 应该用令牌桶算法(Token Bucket)

因为:

  • 秒杀是短时间内爆发大量请求(比如一秒10万)
  • 需要允许短时爆发,但控制总体速率,不能把服务器打挂
  • 令牌桶可以累积一部分爆发流量,保证体验流畅,又不超载

秒杀 Lua 令牌桶限流脚本示例

-- KEYS[1]: 令牌桶的Key
-- ARGV[1]: 最大容量
-- ARGV[2]: 每秒放入多少令牌
-- ARGV[3]: 当前时间戳(秒)

local capacity = tonumber(ARGV[1])
local rate = tonumber(ARGV[2])
local now = tonumber(ARGV[3])

local lastTokens = tonumber(redis.call('hget', KEYS[1], 'tokens') or capacity)
local lastTimestamp = tonumber(redis.call('hget', KEYS[1], 'timestamp') or now)

local delta = math.max(0, now - lastTimestamp)
local newTokens = math.min(capacity, lastTokens + (delta * rate))

if newTokens < 1 then
  return 0
else
  redis.call('hset', KEYS[1], 'tokens', newTokens - 1)
  redis.call('hset', KEYS[1], 'timestamp', now)
  return 1
end

✅ 逻辑:

  • 每过一秒,桶里增加 rate 个令牌
  • 有令牌才能通过扣减,否则拒绝!

小总结

流量模式 推荐算法
秒杀抢购、允许短时冲击 ✅ 令牌桶(Token Bucket)
带宽控制、强制匀速 ✅ 漏桶(Leaky Bucket)

你可能感兴趣的:(node.js,算法,前端,javascript,数据库)