news 2026/9/7 19:51:00

一文搞懂令牌桶限流:平均速率与突发流量的本质(分布式令牌桶实现思路)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
一文搞懂令牌桶限流:平均速率与突发流量的本质(分布式令牌桶实现思路)

一文搞懂令牌桶限流:平均速率与突发流量的本质(分布式令牌桶实现思路)

在做后端系统设计、网关限流或高并发控制时,令牌桶(Token Bucket)是一个绕不开的核心算法。很多人知道它“能限流”,但真正难理解的,是这句话:

令牌桶限制的是平均处理速率,但允许一定程度的突发流量

这篇文章将基于一个完整的问答推导过程,用时间线 + 场景的方式,帮你一次性真正搞懂这句话背后的含义。


一、先明确:令牌桶到底在干什么?

令牌桶算法的核心思想可以总结为一句话:

系统以固定速率往桶中放入令牌,请求只有拿到令牌才能被处理

这里有三个关键要素:

  • 令牌生成速率(rate):比如 100 个 / 秒
  • 桶容量(capacity):比如最多存 100 个令牌
  • 请求消耗令牌:每个请求通常消耗 1 个令牌

限流器本质上做的事情只有一件:

按照时间持续生成令牌,并维护桶中令牌数量不超过上限

当桶满时,新生成的令牌会被直接丢弃。


二、什么叫「限制平均处理速率」?

假设我们设置:

令牌生成速率:100 token / 秒 桶容量:100

这意味着什么?

  • 每 1 秒,系统最多新增 100 个可用处理资格(令牌)
  • 10 秒内,最多生成 1000 个令牌
  • 1 分钟内,最多生成 6000 个令牌

无论请求如何变化:

系统在较长时间尺度上的处理能力是被严格限制的

也就是说,你不可能让系统长期稳定地跑在 200 QPS、300 QPS。

这就是所谓的:

限制的是平均处理速率


三、那什么是「允许突发流量」?

关键就在于:令牌是可以提前积累的

我们还是用上面的参数,通过时间线来看。


四、完整时间线推演(核心理解)

阶段 1:系统启动后的 1 秒内没有请求

t = 0s ~ 1s
  • 限流器持续生成令牌
  • 桶容量是 100

结果:

桶中令牌 = 100(已满)

阶段 2:t = 1s,瞬间来了 100 个请求

注意关键词:瞬间(可能是 1ms 内)

处理结果:

  • 每个请求消耗 1 个令牌
  • 桶中正好有 100 个令牌
100 个请求 → 全部立即通过 桶中令牌 = 0

这一步非常重要:

虽然配置的是 100 QPS,但这一刻的并发远远超过了 100 QPS

这就是:

允许突发流量


五、这为什么不违反「100 QPS」?

因为QPS 是一个“时间平均值”概念

我们看一个完整时间段:

时间段处理请求数
第 0~1 秒0
第 1~2 秒100
合计100

平均下来:

100 / 2 = 50 QPS

完全没有超过限制。

令牌桶限制的是长期平均速率,而不是瞬时峰值。


六、突发之后会发生什么?

阶段 3:突发请求消耗完令牌后

t > 1s 桶中令牌 = 0

此时限流器仍然在工作:

  • 按速率继续生成令牌
  • 100 token / 秒 ≈ 每 10ms 生成 1 个

阶段 4:这时又瞬间来了 100 个请求

假设只过去了 10ms:

桶中令牌 ≈ 1

这 100 个请求会怎样?


七、两种工程实践结果(非常重要)

情况一:不允许等待(最常见于网关)

  • 1 个请求拿到令牌 → 立即通过
  • 剩余 99 个请求 → 直接被限流(返回 429)

此时你的理解:

“只能一个过去”

完全正确的


情况二:允许等待(服务内部常见)

  • 1 个请求立即通过
  • 剩余 99 个请求进入等待队列
  • 后续每生成 1 个令牌,就放行 1 个请求

最终表现为:

输出速率被平滑成 100 QPS

瞬时峰值被削掉,请求被“平滑接住”


八、那「允许一定程度」到底是多少?

答案只有一个:

桶容量(capacity)

  • 桶容量 = 100 → 最多允许瞬间 100 个请求
  • 桶容量 = 1000 → 最多允许瞬间 1000 个请求

公式级理解:

最大突发能力 = 桶容量

九、和漏桶算法的一句话对比

很多人会把令牌桶和漏桶混在一起,这里给你一句话区分:

令牌桶限制平均速率,允许突发;漏桶限制输出速率,不允许突发。


十、一句话总结

你可以这样总结令牌桶:

令牌桶算法通过限制令牌的生成速率来约束系统的长期平均处理能力,同时允许在桶容量范围内消耗提前积累的令牌,从而在短时间内承受一定规模的突发请求;当令牌耗尽后,请求将只能以固定速率被放行或直接被限流。

如果你理解到这里,说明你已经真正理解了:

什么叫“限制平均速率,但允许突发流量”


十一、Redis 分布式令牌桶实现思路(工程实践)

在单机内存中实现令牌桶并不复杂,但在多实例部署(微服务 / 网关集群)的场景下,就必须借助 Redis 来实现分布式限流,以保证多节点之间的令牌一致性。

下面给出一个经典且工程上可落地的 Redis 分布式令牌桶设计思路


1、 核心设计目标

使用 Redis 实现令牌桶,需要解决三个问题:

  1. 令牌全局唯一:多个实例共享同一个桶
  2. 原子性:生成令牌 + 消耗令牌不能被并发破坏
  3. 高性能:限流逻辑必须非常快

因此,Lua 脚本 + Redis 单线程原子执行是最优解。


2、 Redis 中需要维护的关键数据

通常使用一个 Redis Key 表示一个令牌桶,例如:

rate_limiter:{api_name}

该 Key 对应的数据结构中,需要维护:

  • tokens:当前桶中剩余令牌数
  • last_timestamp:上一次补充令牌的时间戳

逻辑上可以理解为:

(tokens, last_timestamp)

3、 请求到来时的完整执行流程

每个请求到来,都会在 Redis 中原子执行以下步骤

  1. 获取当前时间now
  2. 根据时间差计算应补充的令牌数:
new_tokens = (now - last_timestamp) * rate
  1. 更新桶中令牌数(不能超过容量):
tokens = min(capacity, tokens + new_tokens)
  1. 判断是否有足够令牌:
  • 如果tokens >= 1

    • tokens = tokens - 1
    • 请求放行
  • 否则:

    • 请求被限流
  1. 更新last_timestamp = now

以上逻辑必须在一个 Lua 脚本中完成,否则并发下会出现超发令牌的问题。


4、 Lua 脚本伪代码示例

下面是一个简化版伪代码(便于理解思路):

localrate=tonumber(ARGV[1])-- 每秒生成令牌数localcapacity=tonumber(ARGV[2])-- 桶容量localnow=tonumber(ARGV[3])localtokens=tonumber(redis.call('HGET',KEYS[1],'tokens'))orcapacitylocallast=tonumber(redis.call('HGET',KEYS[1],'last'))ornowlocaldelta=math.max(0,now-last)localnew_tokens=delta*rate tokens=math.min(capacity,tokens+new_tokens)iftokens<1thenredis.call('HSET',KEYS[1],'tokens',tokens)redis.call('HSET',KEYS[1],'last',now)return0elsetokens=tokens-1redis.call('HSET',KEYS[1],'tokens',tokens)redis.call('HSET',KEYS[1],'last',now)return1end

返回值:

  • 1→ 请求通过
  • 0→ 请求被限流

5、 为什么 Redis 令牌桶是“软限流”?

Redis 令牌桶本质上是:

  • 立即判断是否有令牌
  • 不负责请求排队

因此它通常用于:

  • API 网关限流
  • 外部接口防刷
  • 秒杀前置拦截

是否“等待令牌”通常由:

  • 客户端重试
  • 上层业务队列

来实现,而不是限流器本身。


6、 工程实践中的几个关键细节

  • 时间单位统一:建议统一使用毫秒时间戳

  • 桶初始化:第一次访问时默认令牌为capacity

  • Key 过期策略:可设置较长 TTL,避免冷 Key 堆积

  • 限流粒度

    • 按接口限流
    • 按用户限流
    • 按 IP 限流

7、 一句话工程总结

Redis 分布式令牌桶通过 Lua 脚本保证限流逻辑的原子性,使多实例系统在共享令牌的情况下,依然能够严格控制整体平均速率,同时保留令牌桶对突发流量的天然支持能力。


版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/7 20:02:33

EmotiVoice在语音翻译软件中的情感保留能力

EmotiVoice在语音翻译软件中的情感保留能力 在一场跨国远程医疗会诊中&#xff0c;医生用急促而关切的语调说&#xff1a;“你的情况需要立刻处理&#xff01;” 如果这句话被翻译成英语后变成平缓、毫无波澜的“Your condition requires immediate attention.”——即便语义准…

作者头像 李华
网站建设 2026/9/7 20:19:52

EmotiVoice开源项目CI/CD流程解析与优化

EmotiVoice开源项目CI/CD流程解析与优化 在AI语音技术飞速发展的今天&#xff0c;用户早已不再满足于“能说话”的机器&#xff0c;而是期待真正“有情感、像真人”的语音交互体验。传统TTS系统受限于固定语调和机械朗读风格&#xff0c;在虚拟助手、游戏NPC、有声内容创作等场…

作者头像 李华
网站建设 2026/9/7 4:50:32

EmotiVoice语音合成在在线课程中的沉浸式体验

EmotiVoice语音合成在在线课程中的沉浸式体验 在今天的在线教育场景中&#xff0c;学习者早已不再满足于“能听清”的课程讲解。他们期待的是更自然、更具感染力的互动体验——就像一位真实教师站在面前&#xff0c;用富有情绪变化的语调引导思考、强调重点、鼓励探索。然而&am…

作者头像 李华
网站建设 2026/9/7 17:07:49

EmotiVoice语音合成在影视后期制作中的潜力

EmotiVoice语音合成在影视后期制作中的潜力 在一部电影的后期剪辑现场&#xff0c;导演突然发现关键情节中的一句台词语气不够强烈&#xff0c;需要从“平静陈述”改为“愤怒质问”。传统流程下&#xff0c;这意味着要重新联系演员、安排录音棚档期、进行多轮试音——整个过程可…

作者头像 李华
网站建设 2026/9/7 15:28:35

Kotaemon异步任务队列设计提升系统响应速度

Kotaemon异步任务队列设计提升系统响应速度 在现代企业级智能对话系统的开发中&#xff0c;一个常见的痛点是&#xff1a;用户刚提出问题&#xff0c;系统却“卡住”几秒甚至更久才开始回应。这种延迟不仅影响体验&#xff0c;还可能引发高并发场景下的服务雪崩。尤其是在检索增…

作者头像 李华
网站建设 2026/9/8 9:20:06

为什么顶级团队都在用Kotaemon做知识问答系统?

为什么顶级团队都在用Kotaemon做知识问答系统&#xff1f; 在企业AI落地的浪潮中&#xff0c;一个看似简单却极具挑战的问题反复浮现&#xff1a;如何让大模型“说真话、有依据、可信任”&#xff1f;尤其是在金融、医疗、法务等高合规要求的领域&#xff0c;幻觉频出、来源不明…

作者头像 李华