服务器与大带宽专家 · 持牌IDC/CDN/ISP服务商
简米科技官网JIANMI TECH
资讯 2026-09-03 更新于 2026-09-03 简米科技 3,666 字 9 分钟阅读

秒杀接口被高频请求打满如何限流?限流方案有哪些?

导读秒杀接口被高频请求打满时,最有效的限流方案是“网关层+应用层”双层限流,用Nginx做入口拦截、Redis做原子计数,配合队列削峰和用户维度放行,而不是简单粗暴地拒绝所有请求,秒杀活动一上线,流量瞬间冲上天灵盖,接口被打满,服务器CPU飙红,用户疯狂点按钮,后台日志刷屏——这不是网络问题,是限流没设计好,作为直……

秒杀接口被高频请求打满时,最有效的限流方案是“网关层+应用层”双层限流,用Nginx做入口拦截、Redis做原子计数,配合队列削峰和用户维度放行,而不是简单粗暴地拒绝所有请求。

秒杀活动一上线,流量瞬间冲上天灵盖,接口被打满,服务器CPU飙红,用户疯狂点按钮,后台日志刷屏这不是网络问题,是限流没设计好,作为直接在线上扛过双11大促的技术人,我用自己的话把整个方案掰开揉碎讲清楚。

秒杀接口被高频请求打满怎么办?先分清限流、熔断与降级

很多开发一谈限流就慌了,看到QPS高就想着直接返回“系统繁忙”,这是典型的混淆概念,限流是控制流量速率,熔断是切断故障节点,降级是牺牲非核心功能保主流程,秒杀场景下,我们主要做的是限流,但熔断和降级也要配合着来,否则下游服务一挂,你限得再狠也没用。

换句话说,限流方案不是单一手段,它是一套组合拳:前置的请求过滤、中端的速率控制、后端的异常兜底,如果只盯着接口本身,你永远堵不住漏洞。

秒杀场景限流算法哪个好?令牌桶还是漏桶?

算法选型直接决定限流效果,行业共识认为,秒杀场景最适合的是令牌桶算法,原因很简单:它允许突发流量,漏桶是平滑流出,哪怕前端瞬间来一万个请求,漏桶也只能每秒处理固定数量,多余的全部排队或丢弃,令牌桶则不同,桶里可以积攒令牌,突发流量进来时只要令牌够,就能一次性放行,不会让用户感觉到明显的卡顿。

具体对比看这张表:

算法 允许突发 实现复杂度 适用场景
固定窗口 简单API配额
滑动窗口 防止临界穿透
漏桶 保护下游系统
令牌桶 中高 秒杀、热点接口

秒杀的特点就是那一两秒内集中爆发,之后流量断崖式下跌,令牌桶能把这股冲动接住,然后以可承受的速率慢慢放给后端,如果用漏桶,前面一千个用户全被拒掉,体验极差,所以我的建议是:网关层用令牌桶,应用层再用计数器或者滑动窗口做二次校验

秒杀接口被高频请求打满如何限流?限流方案有哪些?

网关限流和应用层限流有什么区别?如何配合使用?

这里要回答一个很多团队纠结的问题:限流到底放在哪一层?放Nginx还是写代码里?我的看法是:两层都要做,但分工不同,网关限流负责挡住大部分恶意刷量,应用层限流负责精细控制业务逻辑。

网关层限流:Nginx + Lua 实现令牌桶

Nginx本身就是高并发的王者,每秒能处理几万请求,在Nginx里用Lua脚本实现令牌桶,成本低、见效快,具体做法是:

  • 安装OpenResty(Nginx + LuaJIT)
  • lua_shared_dict里定义一个共享字典存储令牌
  • 每个请求进来时,执行Lua脚本:取当前令牌数,如果能拿到就放行,否则直接返回503

操作路径:在nginx.confhttp块中加lua_shared_dict my_limit 10m,然后在serverlocation里通过access_by_lua_file调用限流脚本,这样即使后端服务全挂了,Nginx也能撑住入口,把绝大多数请求拦截在外面。

应用层限流:Redis + Lua 保证原子性

网关限流管住入口,但有些请求会绕过网关直接打到应用层(比如内部服务调用),或者你需要针对用户ID做更细粒度的判断,这时候就用Redis + Lua脚本

Redis的INCREXPIRE是经典组合,每个用户一个key,比如seckill:user:12345,一秒钟内请求次数超过阈值就拒绝,但注意,INCREXPIRE是两条命令,非原子操作,并发下会出现key过期了但计数没重置的问题,解决办法是写一个Lua脚本,把判断、计数、过期时间放在一个脚本里,Redis保证脚本的原子性。

实操步骤

  1. 定义Lua脚本,逻辑是:如果key不存在,设值为1并设置过期时间;如果存在且小于阈值,加1返回成功;否则返回失败。
  2. 在Java/PHP/Go中调用redis.call执行脚本,但别直接用eval,因为每次传递脚本内容有网络开销,推荐用script load获取SHA,再用evalsha执行。
  3. 设置合理的阈值,比如秒杀接口期望的QPS是1000,那么每个用户的阈值最多设为1,也就是同一秒内同一个用户只能点一次。

这样做的效果是:即使Nginx被攻破,应用层还能防住最后一公里。

秒杀接口被高频请求打满如何限流?限流方案有哪些?

秒杀接口限流方案怎么落地?从压测到上线全流程

限流方案光有理论不行,必须经过实战检验,我总结了一套可复用的落地流程,你们可以照着操作。

第一步:定义核心指标

不要笼统地说“我要限流”,先明确你要保护什么,通常有三层指标:

  • 接口最大吞吐量:比如单机可承载的QPS是2000,那网关限流就设为1500,留出缓冲
  • 依赖服务的承载能力:比如库存系统只能扛500QPS,那秒杀接口的放行速率就不能超过500
  • 用户容忍等待时间:秒杀这种场景,用户最多等3秒,超过3秒再放行也没意义

把这些数据写出来,贴在墙上,后面所有限流参数都以它们为基准。

第二步:压测验证限流效果

很多人上线前不做压测,结果限流参数拍脑袋乱设,正确的做法是用wrkJMeter模拟瞬时高并发。

wrk -t8 -c100 -d10s http://your-api/seckill,观察返回状态码,如果限流生效,应该看到大量503或者自定义的错误码,而不是请求超时或者服务器崩溃,压测时还要看Redis的CPU使用率,如果Redis成了瓶颈,说明限流脚本写得不够高效,需要优化。

第三步:动态调整参数

限流不是一劳永逸,秒杀活动的不同阶段,流量模型不一样,预热阶段可以放宽阈值,让用户提前加购物车;正式开始前5秒收紧阈值,防止脚本刷单;高潮阶段甚至可以采用随机拒绝策略,即每100个请求中只放行40个,其余直接返回“已售罄”,这虽然不是严格意义上的限流,但能有效降低库存服务的压力。

秒杀接口限流如何避免误伤正常用户?动态放行策略

这是限流方案中最容易踩坑的地方,如果只按IP限流,同一个公司楼下共享IP的正常用户全被误伤,如果只按用户ID限流,恶意用户可以注册大量小号绕过,所以需要结合多种维度。

用户维度的请求频率控制

我的做法是:在Redis里维护一个用户行为特征表,包括请求频率、点击间隔、操作路径,正常用户从点击按钮到发送请求,中间会有几百毫秒的页面渲染时间,而脚本刷量的请求间隔极短,通常在10毫秒以内,通过统计用户两次请求的时间差,可以区分是真人还是机器。

具体实现上,用一个ZSET记录用户最近N次请求的时间戳,每次请求进来时用

秒杀接口被高频请求打满如何限流?限流方案有哪些?

ZRANGEBYSCORE取出最近2秒内的记录数,超过阈值就拒绝,这样既限制频率,又能拿到行为数据。

商品维度的库存预扣与排队

限流只是手段,最终目的是保证库存不超卖,光在接口层限流不够,还得在业务层做库存预扣,很多团队的做法是:用户请求进来时,先减库存,再创建订单,但这一步在秒杀场景下容易出问题,因为大量请求同时减库存会导致数据库行锁冲突。

更好的方案是把减库存的操作放到消息队列里,接口层只做校验和入队操作,真正扣减库存由队列消费者异步执行,这样即使瞬时请求很多,队列也能削峰填谷,不会把数据库压垮,队列里的消息需要设置过期时间,比如用户10秒内未支付,自动释放预扣的库存。

常见疑问解答

秒杀接口限流方案中,Redis和Nginx限流哪个更推荐?

两者配合使用,Nginx负责入口层的粗粒度限流,能挡下99%的无效流量;Redis负责应用层的细粒度用户级限流,如果只能选一个,在业务不复杂的场景下选Nginx,因为部署简单、性能最强,如果涉及复杂的业务规则(比如按用户等级、按地区限流),就必须用Redis。

令牌桶算法的参数怎么设置?比如速率和容量

速率设为后端服务能承受的最大QPS,容量设为速率的2到5倍,比如后端能扛1000QPS,那么速率就是1000个令牌/秒,容量可以设3000到5000,这样在流量突增时,系统能在短时间内吸收3000个请求,后续再以每秒1000个的速率处理,但要注意,容量太大了会导致队列积压,用户等太久反而更糟。

秒杀结束后限流策略需要调整吗?

需要,秒杀结束后的30分钟内,依然会有大量用户查看订单状态、申请退款或咨询客服,此时接口的压力虽然变小,但仍高于日常水平,建议秒杀结束后将限流阈值平滑上调,比如从每秒1000逐渐恢复到5000,持续观察监控指标,同时关闭抢购入口,但保留订单查询接口,直到流量完全恢复正常。

可以说,秒杀接口限流没有万能公式,核心思路始终是分层防御、动态调整、兜底保护,把Nginx挡在门口,用Redis卡住每道关口,再用队列和提前预扣稳住库存,你的秒杀系统就能在流量洪峰中稳如磐石,只要压测做到位、参数随流量灵活变,接口被打满就成不了你的噩梦。

分享本文
本文为 简米科技官网 原创,已由运维技术专家审核。转载请注明来源:原文链接
售前咨询 服务热线 售后 邮箱