FastAPI 如何做限流?接口限流常见方案有哪些?
简化版
FastAPI 可以通过中间件、依赖、网关或 Redis 实现限流。单机内存限流简单但多实例不一致;生产常用 Redis 记录用户/IP/API 的计数或令牌桶,或者把限流放到 Nginx、API 网关、云网关层。
详细版
限流用于保护服务,避免单个用户、IP 或接口流量过大拖垮系统。常见算法有固定窗口、滑动窗口、令牌桶、漏桶。FastAPI 里可以在依赖或中间件中检查请求,再决定放行或返回 429。
if too_many_requests(user_id):
raise HTTPException(status_code=429, detail="too many requests")
面试要强调部署形态:多 worker、多实例下,本地 dict 计数不准;分布式限流通常要 Redis 或网关统一执行。
完整版教学
一、为什么需要限流
没有限流时,一个恶意用户或异常客户端可能把接口打满。即使不是攻击,爬虫、重试风暴、前端 bug 也会制造高流量。
正常: 100 req/s
异常: 10000 req/s
限流的目标不是惩罚用户,而是保护整体可用性。
二、限流维度怎么选
可以按 IP、用户、租户、API key、接口路径限流。登录接口常按 IP + 用户名;开放 API 常按 API key;内部接口可能按服务名。
| 维度 | 场景 |
|---|---|
| IP | 防爬、防暴力请求 |
| 用户 | 防单用户滥用 |
| API key | 开放平台 |
| 路径 | 保护重接口 |
维度选错会误伤或漏防。
三、固定窗口和滑动窗口
固定窗口简单:每分钟最多 100 次。但窗口边界会有突刺,例如 12:00:59 打 100 次,12:01:00 又打 100 次,两秒内 200 次。
固定窗口边界突刺:
59s: 100
60s: 100
滑动窗口更平滑,但实现复杂。Redis sorted set 可以实现滑动窗口,但成本比简单计数高。
四、令牌桶和漏桶
令牌桶按固定速率生成令牌,请求消耗令牌,桶里有令牌就放行。它允许一定突发。漏桶则按固定速率流出,更平滑。
令牌桶: 平均限速 + 允许突发
漏桶: 平滑输出
API 限流常用令牌桶,因为真实流量通常有小突发。
五、FastAPI 中放在哪里
可以放依赖里,适合按路由精细控制;也可以放中间件,适合全局控制;还可以在网关层做,减少请求进入应用。
async def rate_limit(request: Request):
...
@app.get("/items", dependencies=[Depends(rate_limit)])
def list_items():
...
网关层抗压更强,应用层能拿到业务用户信息,二者可以组合。
限流越靠前越省资源,越靠近业务越精准。
六、Redis 分布式限流要注意什么
多实例部署时,本地内存计数互不共享。Redis 可以做统一计数,但要保证操作原子性。简单 INCR + EXPIRE 要注意第一次设置过期时间,复杂算法可用 Lua 脚本。
worker A -> Redis
worker B -> Redis
worker C -> Redis
Redis 本身故障时要决定 fail-open 还是 fail-close:是放行请求保证可用,还是拒绝请求保护后端。
七、限流后的用户体验
限流不只是返回 429,还要让调用方知道什么时候重试。开放 API 可以返回 Retry-After、剩余额度、窗口重置时间;内部接口可以打日志和指标,帮助定位异常调用方。
HTTP 429
Retry-After: 30
X-RateLimit-Remaining: 0
如果没有清晰反馈,客户端可能继续疯狂重试,反而让压力更大。
八、监控和灰度
限流阈值不应拍脑袋一次定死。上线前可以先只记录不拦截,观察正常流量分布;上线后监控 429 数量、被限流用户、接口延迟和 Redis 错误率。
observe -> tune threshold -> enforce -> monitor
对核心付费用户、后台任务和普通匿名请求,也可能需要不同限流策略。
九、常见误区与追问
- 误区:用全局 dict 限流就能生产可用。 多进程多实例不共享,重启也丢。
- 误区:所有接口一个阈值。 登录、搜索、下单、静态查询成本不同,阈值应不同。
- 误区:限流只防攻击。 它也防误用、重试风暴和热点流量。
- 追问:为什么返回 429? HTTP 语义是 Too Many Requests。
- 追问:Redis 操作为什么要原子? 并发请求会同时更新计数,非原子会放过超额请求。
- 追问:网关限流和应用限流怎么选? 网关抗压,应用更懂用户和业务。
- 追问:限流后如何提示重试? 可返回 Retry-After 或业务错误码。
十、加强记忆
FastAPI 限流记成“维度、算法、位置、存储”。按谁限、用什么算法、放网关还是应用、计数存在本机还是 Redis,这四个问题决定方案质量。生产多实例别靠本地 dict,关键接口返回 429 并做好监控。