自己写的接口被上游或自己人刷爆,第一反应往往是「加个限流」,但真上手就卡在:按 IP 还是按 Key 分桶、阈值填多少、超了返回什么、用户重试要不要拦。这篇不讲协议兼容层,只讲配置和落地动作:先量基线,再定分桶维度,最后配超额行为和观测,附一张排查顺序表。
自己写的接口被上游或者自己人刷爆,第一反应基本都是「加个限流」。真上手就发现卡住的地方不是协议层,而是几个很土的问题:按 IP 还是按 Key 分桶、阈值到底填多少、超了回什么、用户重试要不要拦。这篇不讲兼容层的实现,只讲配置和落地动作:先量基线,再定分桶维度,最后配超额行为和观测。
顺序很重要。很多人一上来就抄一个「看起来差不多」的数字填进去,结果要么形同虚设,要么把正常业务挡在门外。合理的做法是先知道自己的接口能扛多少,再决定按谁去限制,最后才考虑超了之后怎么处理。
先量基线,别拍脑袋填数字
阈值不是抄来的。先记录单实例在正常负载下的实际吞吐和 P95 延迟,用接口测速类工具跑一轮,得到自己的延迟基线。阈值要建立在这个真实容量上,而不是某个教程里的示例值。基线没有量之前,任何数字都是猜。
- 到 /tools/speed-test 量一遍你接口的延迟基线,拿到正常负载下的真实响应表现
- 再到 /tools 看看有没有现成的换算工具,把「每秒请求数」换算成「同时在跑的请求数」,两个口径别混用
- 口径要分清:限制每秒进入的新请求,是防突发;限制同时在处理的请求,是防资源占满,多数场景两个都要配
- 拿不准就先设一个明显偏松的值跑一周,看实际打到的峰值,再往下压,别一上来就卡死在刚好够用的位置
分桶维度:按谁限、按什么限
分桶决定的是「谁超额谁负责」。常见维度有 API Key、用户 ID、IP、接口路径、全局。至少要做两级:按 Key 加按接口。只做全局限流,一个坏用户就能把所有人拖下水;只做单接口限流,跨接口的刷量又拦不住。
| 维度 | 适用情况 | 什么情况下不适用 |
|---|---|---|
| API Key | 能定位到具体调用方,公私网都适用 | 匿名公开接口拿不到 Key |
| 用户 ID | 站内已登录用户,能追到人 | 未登录流量没有身份 |
| IP | 拿不到稳定身份时的兜底 | 同一出口的用户会互相影响 |
| 接口路径 | 保护耗时长的重接口 | 轻量读接口单独限没意义 |
| 全局 | 最后的兜底保护 | 单独使用会误伤正常业务 |
判断标准就一句话:谁该为超额负责。能定位到具体账号就按账号,只能定位到网络出口就按 IP,两者都定位不到才退回全局兜底。纯 IP 限流在共享出口场景下会误伤,这种情况要叠加匿名设备的软标识,而不是把阈值调高糊过去。
阈值还要按业务等级分档。写操作、付费接口、耗时长的推理类接口给更严的档位;读接口和缓存命中的接口可以放宽。分档不是为了好看,是为了在流量异常时把资源优先留给关键路径。
超额之后怎么办:拒绝、排队还是降级
三条路各有适用范围。直接拒绝最简单,但用户体验差;排队适合任务型调用;降级返回缓存或简版结果,适合可以容忍精度损失的读接口。先想清楚你的接口属于哪一类,再决定用哪条,别默认一律拒绝。
- 直接拒绝
- 实现最省事,适合可重试的读请求和明显的刷量流量
- 排队
- 适合有明确提交语义的任务型调用,要配超时兜底
- 降级返回
- 适合读接口返回缓存或简版结果,要标注数据新鲜度
返回体要给机器可读的信息:状态码用标准的限流语义,响应里带上「多久之后可以重试」,客户端才知道该退避多久。不适用直接拒绝的场景也要说清楚:已经进入计费流程的长任务、用户明确点了提交的写操作,这些更适合排队加超时兜底,别半路把请求丢掉。
还要配合客户端退避。限流侧的返回要让调用方能做指数退避,不然高峰期会形成同步重试的风暴,限流反而变成放大器。具体的退避梯度和恢复步骤,可以对照站内并发与退避相关的文章一起看。
上线后的观测与调参顺序
限流不是配完就完事,得能看到它有没有在工作。至少记这几个字段:时间、Key 或用户标识、接口路径、是否被限流、当前桶内计数、耗时。没有这些字段,事后根本没法复盘阈值定得对不对,只能靠感觉改。
- 第一步 看闸值先确认是不是阈值本身偏低,对照当时的基线数据判断,别急着扩容
- 第二步 看分桶键检查有没有意外聚合,比如所有请求共用一个 Key,或者代理后 IP 全被识别成同一个
- 第三步 看下游确认下游是不是变慢导致在途请求堆积,这种情况限流只是表象,得先修下游
- 第四步 再看流量前面三步都排除后,才怀疑是真实流量上涨,这时候再谈扩容或拆分接口
- 阈值调整留记录:改了什么、为什么改、改完观察了多久,否则半年后没人说得清数字的来历
- 按天和按周各看一眼被限流比例,长期接近零说明闸值过松,起不到保护作用
- 被限流比例长期高于正常水位,说明该扩容或者把接口拆开了,别一直靠调阈值扛
- 具体该看哪些长期指标和趋势,到 /price-watch 这类追踪页面核对当时的数字更靠谱
常见问题
阈值到底填多少才合适?
没有通用数字,先从你的实测容量往下留一档余量开始。做法是跑一轮压测或看历史峰值,取单实例稳定处理的量,再按集群实例数放大。写完先偏松观察一段时间,看真实峰值再收。想省事可以参考同量级接口在 /models 和站内用量相关页面里的公开口径做横向参照,但最终还是以你自己的压测为准。
限流和并发限制是一回事吗?
不是。限流管的是单位时间进入的请求数量,超了就拒;并发限制管的是同一时刻正在处理的请求数,超了通常排队。两者要配合:只限速率,突发长请求一样能把内存打满;只限并发,短时间内的高频小请求又会把下游刷爆。分别设阈值,别用一个数字糊过去。
被限流的用户怎么让他恢复?
回复里给明确的等待时间,指出是哪个维度触发的,客户端据此退避重试。别只在日志里记一笔、对外返回一个含糊的错误。如果是对外开放接口,最好把当前用量和剩余额度也带上,方便调用方自查。触发原因、恢复步骤和长期规避可以另外对照站内限流恢复类文章看。