令牌桶和漏桶算法使用场景解析
文章目录
- 什么时候用令牌桶,什么时候用漏桶算法??
- 先放结论
- 两个算法一眼看懂
- 什么时候选令牌桶?
- 什么时候选漏桶?
- 组合用法(90% 的真实系统都会这么干)
- 小结记忆
- 对令牌桶和漏桶组合用法再次详细叙述一下,以小红书生活社区系统为例子
- 为什么要 **“令牌桶 → 漏桶”** 组合?
- 1. 小红书请求链路示例
- 2. 组合在小红书的 **四个高频场景**
- 3. 配置与调优步骤(落地到小红书)
- 4. 代码/配置片段示意
- 5 · 常见误区 & 小红书踩坑实录
什么时候用令牌桶,什么时候用漏桶算法??
先放结论
场景特征 | 令牌桶(Token Bucket) | 漏桶(Leaky Bucket) |
---|---|---|
是否允许突发流量 | ✔ 允许,可在桶里先攒“额度”,瞬时放量 | ✘ 不允许,出流量永远是匀速 |
对下游的压力 | 瞬时可能出现高并发,需要下游有一定缓冲或弹性 | 始终平滑,几乎不会压垮下游 |
对实时性/时延要求 | 突发时延小,整体时延可控 | 峰值被“削平”,高峰请求会排队、时延增大 |
典型用例 | API 网关限流、微服务之间“削峰”但保留突发、手机套餐计费 | 交换机/路由器排队、日志写入磁盘、打印任务、银行转账出账口 |
两个算法一眼看懂
关键词 | 令牌桶 | 漏桶 |
---|---|---|
本质 | “拿令牌才可通过” | “进水随意,出水匀速” |
控制维度 | 入流(允许多久发多少) | 出流(确保永远固定速率) |
可配置项 | 生成速率 r、桶容量 b | 漏出速率 r、桶容量 b |
能否积攒额度 | 可以:桶里最多存 b 个令牌 | 可以:桶里最多排队 b 个请求 |
流量视角 | 突发→滑动平均 ≤ r | 任何时刻 ≤ r |
什么时候选令牌桶?
- 业务本身就是“偶有高峰”
例:电商秒杀开始前 5 秒,令牌桶能攒够令牌,瞬间放行指定量请求;后续再匀速补充。 - 下游能短暂扩容或有缓冲区
比如使用异步队列、K8s 自动扩缩容,可吃掉短时突发。 - 需要按“总量 + 峰值”计费/统计
运营商对流量计费:保证平均速率,但允许你瞬时用掉“未用额度”。 - API 限流希望“好人优先”
正常流量积攒令牌,机器人/爬虫持续刷会很快耗尽令牌,被限速。
一句话:令牌桶在乎“总量控制 + 瞬时弹性”。
什么时候选漏桶?
- 下游“吃不了”任何峰值,只能匀速消费
打印机、磁带机、磁盘顺写、第三方支付接口 QPS 固定。 - 希望彻底削峰平谷,保证稳定输出
视频流推送、实时音频、网络芯片队列,抖动越小越好。 - 时延可被牺牲换取稳定
排队时间增加也没关系,例如批量日志落盘。 - 实现简单、资源可预估
只要求一个固定速率,不需要动态计算剩余令牌。
一句话:漏桶在乎“绝对平滑 + 下游安全”。
组合用法(90% 的真实系统都会这么干)
- 入口令牌桶 —— 允许合规突发,把“洪峰”削到可控范围。
- 出口漏桶 —— 对真正娇贵的依赖再做一次匀速下沉。
这样既不失灵活性,又能保护最脆弱的环节。很多 API 网关、CDN、大型分布式系统限流都是“先令牌桶,后漏桶”。
小结记忆
- 令牌桶:能攒钱、能一次性花;平均不能超标。
- 漏桶:只能领死工资;永远 1、1、1… 匀速走。
选哪个?看你要不要“突发权”。如果答案是“要”—→令牌桶;如果答案是“绝不能”—→漏桶。
对令牌桶和漏桶组合用法再次详细叙述一下,以小红书生活社区系统为例子
为什么要 “令牌桶 → 漏桶” 组合?
在真实的大型社区里——小红书就是典型——没有一种单独的限流算法能同时满足「用户体验」和「核心依赖安全」 两个目标:
目标 | 令牌桶能做到 | 漏桶能做到 |
---|---|---|
秒级突发场景(双 11、明星发笔记秒赞)依然“秒开” | ✔ | ✘ |
保护下游(数据库、推荐 RPC、支付)绝不被瞬时打爆 | ✘ | ✔ |
所以工业界普遍做法是:入口先令牌桶,出口再漏桶。下面用小红书的典型流量路径来拆一遍。
1. 小红书请求链路示例
App/Web ➜ CDN ➜ API Gateway ➜ Notes Service ➜│ │(令牌桶限流) (漏桶匀速入库 + MQ)
-
API Gateway / 边缘网关(令牌桶)
- 粒度:用户 ID + 接口(
/notes/publish
、/notes/like
等) - 配置示例:
- 桶容量 B = 120(允许 2 分钟的剩余额度)
- 令牌速率 R = 60 req/min(每人每分钟 60 次发帖接口)
- 效果:
- 正常人偶尔连点「发布」也能秒过。
- 连续脚本刷请求会瞬间耗空令牌,得到 429。
- 粒度:用户 ID + 接口(
-
业务微服务(漏桶)
- 场景:
Notes Service
里写数据库、调用内容审核、下发特点 feed 打分。 - 实现:
入队:任意速率 出队:固定 5 k/s → MySQL & Redis & AI 审核
- 参数:
- 漏速 L = 5 000 req/s(后端表的写入 QPS 压测上限)
- 桶深度 Q = 20 000(≈4 秒峰值缓冲)
- 效果:
- 当明星空降带来 10 k/s 发布洪峰时,队列顶多攒 4 秒即被消化。
- 如果洪峰持续更久,队列溢出触发降级(写失败重试 / 回退到异步草稿)。
- 场景:
2. 组合在小红书的 四个高频场景
场景 | 入口令牌桶 | 出口漏桶 | 额外策略 |
---|---|---|---|
笔记发布 | 用户维度限流,允许一键连发 | 图片转码、AI 审核匀速写入 | 超队列 10 s 回退草稿,告知稍后发布 |
点赞/收藏 | 用户-接口维度令牌,防止机器脚本 | 点赞写 Redis,不需要漏桶;但写 MySQL 日志走漏桶 | 后端异步批量合并落库 |
搜索热词 | IP + 用户令牌桶,挡住爬虫高频搜索 | ES 查询也做漏桶,匀速 2 k/s | 热词命中缓存直接返回 |
直播间打赏 | 用户余额操作需闪电响应→入口令牌桶 + 内存预扣 | 金额入账、流水写账务库用漏桶 | 账务库用 XA 事务,漏速按 TPS 上限 |
3. 配置与调优步骤(落地到小红书)
- 抓历史峰值
- 查询「双 11」「618」「明星生日」当天 每 10 秒 的 QPS 波峰。
- 先配令牌桶
B ≈ R × 可接受峰值持续秒数
(可逆算为「用户能连点多少次不被限」)。
- 测后端极限
- 对 MySQL / ES / 推荐 RPC 压测,得出
L_max
。
- 对 MySQL / ES / 推荐 RPC 压测,得出
- 配漏桶
L = 0.8 × L_max
预留 20 % 余量。Q = L × 回滚/降级开销秒数
(如 4 秒)。
- 双阈值监控
- 队列长度 > 0.6 Q:灰度告警,加实例。
- 队列长度 > 0.9 Q:熔断低优接口或触发静默降级。
4. 代码/配置片段示意
# 网关级(Kong / Envoy)
rate_limiting:name: notes_publish_token_bucketcapacity: 120 # Btokens_per_interval: 60 # Rinterval: 60sredis_slot: user_id# Notes Service(Go 伪码)
leaky := NewLeakyBucket(leakRate = 5000, // LqueueDepth = 20000, // Q
)
for req := range inboundChan {if !leaky.Allow(req) {metrics.Publish("overflow")return ErrBusy // 触发降级}process(req) // 写库 + 审核 + MQ
}
5 · 常见误区 & 小红书踩坑实录
# | 误区(Anti-Pattern) | 真实后果 / 事故现场 | 根因分析 & 解决策略 |
---|---|---|---|
1 | 只做令牌桶,不做漏桶 | 2024 年某明星直播带货高峰,瞬时发帖 QPS 从 3 k 飙到 12 k;MySQL 主从延迟 30 s,导致点赞丢失、推荐时序错乱 | 令牌桶放行突发,却没人“刹车”数据库 → 下游被冲垮 |
2 | 漏桶漏速设太小 | 春节活动,漏速仅 2 k/s;排队深度 20 k 很快塞满,发布接口耗时 > 10 s,被大量用户投诉卡顿 | 峰值持续时间被低估;队列深度设计与峰值不匹配 |
3 | 把漏桶做在网关层“全局公用” | 统一队列里既有搜索也有发帖;一次搜索风暴让发帖延迟 5 s——出现“木桶效应” | 业务优先级不同,却共用同一桶 |
4 | 令牌桶容量(B)设过大 | 群控脚本低频养号,10 min 内攒满 600 token,随后一键爆发 → 机器流量混在真人里逃过风控 | 运维按“用户体验”放大 B,却忽视恶意攒桶 |
5 | 令牌桶按 IP 而非用户限流 | 学校/公司 NAT 出口下所有用户共享同一 IP,晚高峰点赞被误杀(429) | 多人共用 IP → token 争抢 |
6 | 漏桶没有溢出策略 | 活动推送 Bug 触发 50 k/s 写库,队列溢出后 JVM 直接 OOM | 队列满时仍强行入列 |
7 | 未监控桶内指标 | 一次 Gradual Release 没人关注队列水位,5 分钟后才发现 MySQL 延迟;事故扩大 | 队列长度、等待时长无可观测 |
8 | 跨机房分布式令牌桶未同步 | A 机房峰值被挡住,B 机房因未同步令牌被打爆;两边用户体验不一致 | 本地缓存令牌导致“各自为政” |
9 | 漏桶排队里混入长耗时任务 | AI 审核超时 2 s,阻塞后面的 1000 条快速写入请求 | 漏桶只是匀速出队,内部仍可能被慢请求“撑爆” |
10 | 冷热启停未预热令牌桶 | 服务重启后令牌桶空,导致 10 s 内 90 % 用户请求 429 | 冷启动没有令牌 |
经验总览:先用数据推“峰值 × 持续时间”,再对照下游极限设 B, R, L, Q;并且 每个微服务自己兜底、监控可观测、溢出有降级。