news 2026/7/22 11:11:23

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

作者头像

张小明

前端开发工程师

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/7/18 23:33:45

Kotaemon视频内容摘要生成实验记录

Kotaemon视频内容摘要生成实验记录 在音视频内容爆炸式增长的今天&#xff0c;如何从数小时的讲座、会议或教学录像中快速提取核心信息&#xff0c;已成为知识工作者和企业面临的一大挑战。传统做法依赖人工听看并撰写摘要&#xff0c;效率低、成本高&#xff1b;而直接使用大语…

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

用Matlab探索齿轮系统的奥秘:刚度计算与动力学响应

Matlab计算齿轮啮合刚度计算&#xff0c;包括赫兹刚度弯曲刚度等子程序。 以及六自由度齿轮系统动力学响应计算。在机械传动领域&#xff0c;齿轮系统扮演着至关重要的角色。深入了解齿轮的啮合刚度以及系统的动力学响应&#xff0c;对于优化设计、提高性能和延长使用寿命都有着…

作者头像 李华
网站建设 2026/7/21 13:20:27

【node阅读-0】下载编译node

一、下载编译-windows build 工具要求安装方式Visual Studio 2022版本 17.13 或更高必须选 “Desktop development with C” workload必须安装 ClangCL 组件&#xff1a;- C Clang Compiler for Windows (Microsoft.VisualStudio.Component.VC.Llvm.Clang)- MSBuild support f…

作者头像 李华
网站建设 2026/7/22 5:03:37

EmotiVoice支持动态情感过渡,实现平滑情绪变化

EmotiVoice&#xff1a;让语音真正“动情”的合成引擎 在虚拟偶像的直播中&#xff0c;一句从温柔期待逐渐转为委屈落泪的台词&#xff0c;让弹幕瞬间刷满“破防了”&#xff1b;在互动叙事游戏中&#xff0c;NPC因玩家选择而情绪骤变&#xff0c;声音颤抖着说出那句“我信任你…

作者头像 李华
网站建设 2026/7/22 10:32:43

EmotiVoice推理时显存占用优化方案(适用于低配GPU)

EmotiVoice推理时显存占用优化方案&#xff08;适用于低配GPU&#xff09; 在AI语音技术飞速发展的今天&#xff0c;越来越多开发者希望将高表现力的文本转语音&#xff08;TTS&#xff09;系统部署到本地设备。EmotiVoice作为一款支持多情感合成与零样本音色克隆的开源TTS引擎…

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

EmotiVoice支持HTTPS加密传输,保障数据安全

EmotiVoice 支持 HTTPS 加密传输&#xff1a;构建安全可信的语音合成服务 在智能语音技术日益普及的今天&#xff0c;从虚拟助手到有声读物、在线教育乃至游戏中的角色对话&#xff0c;文本转语音&#xff08;TTS&#xff09;系统正深度融入我们的数字生活。开源项目如 EmotiVo…

作者头像 李华