限流详解:常见业务场景与四种核心算法
一、什么是限流
限流,顾名思义就是:
限制进入系统的流量。
在高并发系统中,如果短时间内大量请求同时进入服务器,很容易导致:
线程池耗尽
数据库连接池耗尽
CPU 飙高
内存压力增大
下游服务被打垮
最终导致系统雪崩
所以限流的核心目的就是:
通过限制请求速率、并发量或者资源使用量,保护系统不被瞬时流量冲垮。
例如系统最多只能承受:
1000 QPS
那么即使瞬间进来:
5000 QPS
也只允许其中一部分请求进入系统,其余请求可以:
直接拒绝
排队等待
降级处理
返回友好提示
因此,限流本质上是一种:
系统保护机制。
二、为什么需要限流
系统的资源永远都是有限的。
例如:
CPU 有上限
线程数有上限
数据库连接数有上限
Redis 连接数有上限
第三方 API 调用次数有上限
如果不做限流,当请求量超过系统承载能力时,就会出现:
请求越来越慢
↓
请求开始堆积
↓
线程被占满
↓
数据库连接耗尽
↓
更多请求超时
↓
系统雪崩
所以限流的核心思想可以理解成:
宁愿拒绝一部分请求,也不要让整个系统全部挂掉。
三、常见的限流业务场景
1. 短信验证码 / 邀请码发送
例如:
用户注册发送验证码,1 分钟只能发送一次。
可以限制:
同一个手机号:
1 分钟最多发送 1 次
例如 Redis:
sms:13800138000
设置:
TTL = 60 秒
如果 Key 已经存在:
请勿频繁发送验证码
这种属于:
用户维度限流。
2. 第三方接口调用次数限制
例如第三方平台规定:
每天最多调用 10000 次
那么系统就需要维护:
third_api:2026-09-01
记录当天已经调用多少次。
例如:
当前调用次数:9999
还能调用。
如果:
当前调用次数:10000
后续请求就需要:
拒绝
延迟
排队
第二天再执行
这种属于:
资源配额限流。
3. 防止突发流量打垮服务
假设服务器正常只能承受:
2000 QPS
突然因为:
秒杀
热点新闻
营销活动
爬虫
恶意请求
流量暴涨到:
20000 QPS
如果所有请求直接进入系统,很容易把服务器打挂。
因此可以限制:
最多允许 2000 QPS
其余请求:
拒绝
排队
降级
这种属于:
系统入口限流。
4. 接口防刷
例如:
登录接口
注册接口
评论接口
领取优惠券
抽奖接口
点赞接口
可以限制:
同一个 IP:
1 分钟最多请求 100 次
同一个用户:
1 秒最多请求 5 次
防止:
爬虫
恶意脚本
接口攻击
重复提交
5. 秒杀系统
例如:
库存只有 1000 件
但瞬间有:
10 万用户请求
没有必要让所有请求都进入数据库。
可以在网关层直接限流:
只允许部分请求进入核心系统
配合:
缓存
消息队列
库存预扣
保护数据库。
6. API 网关限流
例如:
/user/**
/order/**
/pay/**
不同接口设置不同 QPS。
比如:
普通查询接口:
1000 QPS
订单创建接口:
300 QPS
支付接口:
100 QPS
这种属于:
接口维度限流。
7. 多租户 / SaaS 系统
例如:
普通用户:
100 次 / 分钟
VIP 用户:
1000 次 / 分钟
企业用户:
10000 次 / 分钟
这类属于:
配额型限流。
四、常见限流维度
实际业务中,限流往往不仅仅是限制整个系统。
还可以按不同维度进行。
例如:
系统级别
接口级别
用户级别
IP 级别
设备级别
租户级别
手机号级别
第三方平台级别
例如:
/user/login
同一个 IP:
1 分钟 100 次
同一个账号:
1 分钟 10 次
可以同时存在多个限流规则。
五、常见限流算法
常见的限流算法主要有四种:
固定窗口
滑动窗口
漏桶算法
令牌桶算法
六、固定窗口算法
固定窗口是最简单的一种限流算法。
例如:
1 分钟最多请求 100 次
把时间划分成一个个固定窗口:
10:00 - 10:01
最多 100 次
10:01 - 10:02
最多 100 次
在一个窗口里面维护一个计数器:
count++
如果:
count <= 100
允许访问。
否则拒绝。
到了下一个窗口:
count = 0
重新计数。
例如 Redis:
limit:user:1001:10:00
每请求一次:
INCR
并设置:
EXPIRE 60
固定窗口的问题
最大的问题是:
窗口边界可能出现双倍流量。
例如限制:
1 分钟最多 100 次
用户在:
10:00:59
瞬间请求 100 次。
紧接着:
10:01:00
窗口重置。
又请求 100 次。
于是:
1 秒左右
实际进入了 200 个请求
这就是:
临界值问题。
所以固定窗口实现简单,但流量控制不够平滑。
七、滑动窗口算法
滑动窗口是固定窗口的优化。
固定窗口:
10:00 - 10:01
10:01 - 10:02
窗口是死的。
滑动窗口则始终统计:
当前时间往前推一段时间。
例如:
当前时间 10:01:20
统计:
10:00:20 - 10:01:20
这一分钟里面的请求数量。
假设规则:
最近 60 秒最多 100 次
那么每次请求进来:
删除 60 秒以前的数据
↓
统计最近 60 秒请求数
↓
小于 100
允许
↓
大于等于 100
拒绝
Redis 中非常适合使用:
ZSET
实现。
例如:
score = 请求时间戳
member = requestId
然后:
ZREMRANGEBYSCORE
删除过期数据。
再:
ZCARD
统计窗口内请求数。
滑动窗口的优点
相比固定窗口:
更加准确
更加平滑
不会出现明显的窗口边界问题
缺点是:
需要记录更多请求数据
实现成本更高
八、漏桶算法
漏桶算法可以想象一个水桶。
请求就像水:
请求
↓↓↓↓↓↓↓↓
┌──────────┐
│ │
│ 水桶 │
│ │
└─────┬────┘
│
↓
固定速度流出
请求可以快速进入桶里。
但是系统处理请求的速度是固定的。
例如:
桶容量:100
流出速度:10 个 / 秒
即使瞬间来了:
100 个请求
系统也只会按照:
10 个 / 秒
慢慢处理。
如果桶满了:
后续请求直接拒绝
所以漏桶算法最大的特点:
强制请求按照稳定速率流出。
特别适合:
保护下游系统
消息发送
调用第三方接口
稳定消费速度
九、漏桶算法的特点
优点:
流量非常平滑
可以很好保护下游服务
缺点:
不允许突发流量。
即使系统现在很空闲:
突然来了 100 个请求
也只能:
一个一个按照固定速度处理
所以对于需要允许一定突发能力的系统,漏桶会显得比较严格。
十、令牌桶算法
令牌桶是实际系统中非常常见的一种限流算法。
想象有一个桶:
┌──────────┐
│ ● ● ● ● │
│ ● ● ● │
│ │
└──────────┘
桶里面放的是:
令牌 Token
系统按照固定速率向桶里放令牌。
例如:
每秒生成 10 个 Token
每个请求进来必须:
拿到 1 个 Token
才能执行。
如果拿不到:
拒绝请求
令牌桶为什么允许突发流量
假设:
桶容量 = 100
令牌生成速度 = 10 / 秒
如果系统一段时间没有请求:
桶里面积累了 100 个 Token
突然来了:
100 个请求
它们可以瞬间拿走:
100 个 Token
全部执行。
然后后续请求只能按照:
10 个 / 秒
继续执行。
所以:
令牌桶既能限制长期平均速率,又允许一定程度的瞬时突发流量。
这也是为什么很多系统非常喜欢令牌桶。
十一、漏桶和令牌桶的区别
这是非常经典的面试题。
漏桶:
请求进入桶
↓
按照固定速率出去
核心控制的是:
输出速度。
令牌桶:
系统生成 Token
↓
请求抢 Token
↓
抢到才能执行
核心控制的是:
请求是否获得执行资格。
最大的区别:
漏桶:
不允许明显突发流量
令牌桶:
允许一定突发流量
可以简单理解:
| 算法 | 是否支持突发流量 |
|---|---|
| 固定窗口 | 支持,但可能失控 |
| 滑动窗口 | 一定程度支持 |
| 漏桶 | 基本不支持 |
| 令牌桶 | 支持 |
十二、四种算法怎么选择
可以简单这么选。
固定窗口
适合:
实现简单
精度要求不高
业务量较小
例如:
短信验证码:
1 分钟一次
滑动窗口
适合:
接口防刷
用户请求频率控制
对限流准确性要求较高
例如:
最近 1 分钟最多请求 100 次
漏桶
适合:
必须严格控制下游处理速度
例如:
第三方接口只能稳定接受
100 请求 / 秒
令牌桶
适合:
系统入口限流
API 网关
微服务限流
秒杀
允许短时间突发流量
实际工程中非常常见。
十三、实际业务如何选择
前面三个需求可以直接对应。
用户注册发送邀请码,一分钟一次
建议:
Redis Key + TTL
或者:
固定窗口
因为:
业务简单
不要求毫秒级精度
第三方接口每天只能调用 1 万次
可以使用:
每日计数器
+
固定窗口
例如:
third-api:20260901
每天重置。
防止突发流量打垮服务器
更适合:
令牌桶
例如:
平时允许 1000 QPS
桶容量 2000
这样:
长期平均速度被限制
+
系统又能承受一定突发流量
这是网关、微服务入口非常常见的方案。
十四、限流一般放在哪里
实际系统中,限流可以存在多个层级:
用户
↓
Nginx
↓
API Gateway
↓
微服务
↓
具体接口
↓
数据库 / 第三方服务
例如:
Nginx
负责粗粒度流量控制
Gateway
负责用户、IP、接口维度限流
Service
负责具体业务限流
Redis
负责分布式限流计数
通常不会只做一层限流。
十五、限流之后怎么处理请求
触发限流并不一定只能直接报错。
常见处理方式包括:
直接拒绝
排队等待
快速失败
降级处理
进入消息队列
返回缓存数据
稍后重试
例如 HTTP 接口可以返回:
HTTP 429 Too Many Requests
表示:
请求过于频繁。
十六、限流的核心总结
限流的本质就是:
控制进入系统或者进入某个资源的请求速度,避免流量超过系统承载能力。
常见算法:
固定窗口
滑动窗口
漏桶
令牌桶
核心区别:
固定窗口:
简单计数
滑动窗口:
精确统计最近一段时间
漏桶:
固定速度处理请求
令牌桶:
固定速度产生令牌,允许一定突发流量
实际业务场景:
短信验证码防刷
登录接口防刷
第三方 API 配额
秒杀流量控制
API 网关
微服务保护
爬虫防护
支付接口保护
多租户配额
资源访问限制
如果只记住一句话:
限流不是为了让系统处理更多请求,而是在系统能力有限的情况下,控制请求进入速度,从而保护整个系统的稳定性。