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

七层防御思路怎样应对海量重复请求,如何设计高并发限流防刷机制

导读七层防御思路应对海量重复请求,核心做法是把“去重”动作从客户端一路铺到数据库,每层拦住一部分重复流量,最终只有极少数真正落到数据层,海量重复请求为什么危险重复请求会让系统在短时间内做大量无用功,用户连续点击“提交订单”,前端没禁用按钮,1秒发出7个请求,网络超时后客户端自动重试,服务端已经成功处理,又收到相同报……

七层防御思路应对海量重复请求,核心做法是把“去重”动作从客户端一路铺到数据库,每层拦住一部分重复流量,最终只有极少数真正落到数据层。

海量重复请求为什么危险

重复请求会让系统在短时间内做大量无用功,用户连续点击“提交订单”,前端没禁用按钮,1秒发出7个请求,网络超时后客户端自动重试,服务端已经成功处理,又收到相同报文,脚本用同一组参数高频请求接口,绕过前端直接打后端。

这些重复流量带来的后果很直接:

  • 数据库连接池被打满,正常请求排队超时。
  • Redis热点key被反复读写,缓存击穿风险上升。
  • 库存被重复扣减,订单表出现多条相同记录。
  • 消息队列堆积,消费者处理不过来。

单点防御不够,前端防抖只能管住手滑,挡不住脚本,数据库唯一索引是最后的底线,但等请求冲到数据库再拦,连接和事务开销已经产生。要真正扛住海量重复请求,必须分层设防。

接口防重复提交最佳方案:七层防御怎么搭

七层防御不是七种孤立技术,而是从请求入口到数据落地的完整链条,每一层只做自己最擅长的事,把重复请求逐层过滤。

  1. 客户端防抖与按钮禁用
  2. CDN或边缘节点缓存
  3. API网关限流与防重
  4. 应用层Token与幂等校验
  5. 分布式锁与缓存去重
  6. 数据库唯一约束
  7. 消息队列异步削峰

下面按层拆开讲。

高并发下如何防止重复提交?先分清重复来源

重复请求的来源不同,防御重点也不同。

  • 用户手滑:连续点击按钮、双击提交,靠客户端防抖和按钮禁用解决。
  • 网络重试:请求超时后SDK自动重发,服务端已处理成功但响应丢失,靠幂等设计解决。
  • 恶意脚本:绕过前端直接调接口,换IP刷参数,靠网关限流、验证码、设备指纹解决。

分清来源后,才能把七层防御安排到正确位置。

客户端防抖和按钮禁用:最廉价的第一层

用户点击提交按钮后,立即设置disabled=true,请求返回前不允许再次点击,防抖函数设置300毫秒延迟,连续触发只发送最后一次,这层成本极低,能拦住相当一部分手滑流量。

七层防御思路怎样应对海量重复请求,如何设计高并发限流防刷机制

但客户端永远不可信,浏览器控制台能改状态,脚本不经过页面直接请求接口,所以这一层只是减少压力,不能作为安全边界。

CDN与边缘缓存:让重复请求根本到不了源站

对商品详情、活动页、静态配置这类读接口,CDN直接缓存响应内容,重复请求在边缘节点就被消化,根本不回源站,配置上注意两点:缓存键要忽略无关排序参数,避免同样内容因为参数顺序不同产生多份缓存,缓存时长根据业务容忍度设置,秒杀场景通常设几秒到一分钟。

CDN能拦住的重复请求以读为主,写请求必须穿透到应用层,不能盲目缓存。

API网关限流与防重:统一入口的守门人

网关是所有流量的第一道服务端关卡,限流按IP、用户ID、接口路径三个维度做令牌桶或漏桶控制,超阈值直接返回429,防重可以在网关层用Redis保存请求指纹,比如MD5(userId+uri+body),TTL内相同指纹直接返回缓存结果或重复标记。

国内电商大促场景下,网关还会对同一用户对同一SKU的查询做去重,减少下游库存服务压力,这层需要额外部署Nginx、Kong或Sentinel,维护成本中等,但效果明显。

应用层Token与幂等校验:业务防重的核心

写请求的重复提交,靠业务幂等机制解决,常用两种方式:

  • 页面Token:进入表单页时后端签发随机token,提交时携带token,后端校验并立即删除,重复提交时token已不存在,直接返回失败。
  • 业务幂等号:客户端生成全局唯一requestId,服务端用Redis执行SET requestId 1 NX EX 60,设置成功说明首次处理,失败说明重复,直接返回上次结果或“请勿重复提交”。

Redis命令示例:

SET order:request_id:{userId}:{requestId} 1 NX EX 60

返回nil表示key已存在,属于重复请求。

分布式锁防止重复提交:加锁粒度与过期时间怎么定

对于同一用户对同一订单的支付、取消等强一致操作,可以用分布式锁串行化处理。

实操要点:

  • 锁key粒度精确到“用户+操作+业务对象”,例如

    七层防御思路怎样应对海量重复请求,如何设计高并发限流防刷机制

    lock:pay:order:1001:user:2002

  • 过期时间设10到30秒,具体看业务最长处理时间,不要设太长,否则误锁。
  • 释放锁用Lua脚本比较value再删除,防止误删其他线程刚获取的锁。
  • 获取锁失败时返回明确错误码,客户端不要自动重试,转去查询接口确认状态。
SET lock_key {uniqueValue} NX PX 30000

锁能降低数据库并发冲突,但不能保证数据绝对一致,网络分区、锁过期、GC停顿都会让锁失效。

数据库唯一索引防重复插入:最后一道硬防线

不管前几层漏多少,数据库唯一约束能保证数据不会重复落盘,订单表建唯一索引:

ALTER TABLE orders ADD UNIQUE KEY uk_order_no (order_no);

插入时捕获唯一键冲突,返回已有记录,这一层是数据一致性的最终底线,可靠性最高,唯一索引会带来写入性能损耗,但相比重复数据造成的业务事故,这个开销多数情况下可以接受。

消息队列异步削峰:把同步重复变成可消化

非实时操作不要同步处理,用户提交后,先写入消息队列,由消费者异步处理,消费者必须做幂等消费:用业务唯一键查去重表,存在则跳过,重复消息依靠去重表或唯一键排除,不会重复执行扣款或发货逻辑。

服务器防重复请求策略:限流与降级怎么配合

去重解决“同一个请求来多次”,限流解决“不同请求来太多”,两者配合才能扛住海量流量洪峰。

  • 限流:在网关或应用层设置QPS阈值,超限直接拒绝,返回429或降级页面,令牌桶适合允许突发流量的场景,漏桶适合平滑流量。
  • 降级:核心链路关闭非关键功能,比如大促时商品推荐、积分查询降级,把资源留给下单、支付主链路。
  • 熔断:下游服务错误率过高时,快速失败不再调用,避免级联故障。

行业共识认为,限流和降级没有统一标准,阈值需要根据压测结果动态调整,压力测试给出的容量数据,比拍脑袋定的阈值可靠得多。

各层防御成本与效果对比:

七层防御思路怎样应对海量重复请求,如何设计高并发限流防刷机制

防御层 主要工具 实施成本 拦截效果
客户端 前端防抖、按钮禁用 极低 拦截手滑
边缘层 CDN缓存 拦截静态重复
网关层 Nginx/Kong/Sentinel 限流+基础防重
应用层 Redis+Token/幂等 中高 业务级防重
数据层 唯一索引 最终兜底
队列层 RocketMQ/Kafka 中高 异步削峰

七层防御实施顺序与取舍

小项目不用七层全上,至少保证客户端、应用层、数据库三件套,就能解决大多数重复提交问题,中大型系统再补网关限流、CDN缓存和消息队列。

成本方面,开源组件如Redis、Nginx、Sentinel没有许可费,但需要人力部署维护,商业API网关按请求量收费,省事但在大流量下会产生明显费用,国内不少团队会先用开源方案扛过早期,等业务量稳定再评估商业方案。

七层防御的本质,是让重复请求在离数据越远的地方被拦住,成本越低。 每一层都在为下一层减轻压力,最终保证数据层只处理必要的请求。

Q&A

重复请求攻击怎么防御?

从网络层开始限流,识别同IP高频同参数请求,触发验证码或临时拉黑,应用层必须做幂等校验,用Redis或Token机制拦截重复提交,数据库加唯一约束,保证即使前几层漏掉也不会产生脏数据。

前端防抖和禁用按钮能防重复提交吗?

能拦住大多数用户手滑场景,但对脚本、网络重试、多端同时操作无效,前端永远可以被绕过,所以后端幂等是底线,不能只靠前端。

分布式锁和数据库唯一索引哪个更可靠?

数据库唯一索引是最可靠的,因为它是数据落盘前的强制约束,不依赖外部组件状态,分布式锁能减少数据库冲突,但可能因网络抖动或过期时间设置不当而失效,两者配合使用,锁负责拦截大部分重复流量,唯一索引负责最终兜底。

在高并发场景下,重复请求无法完全消灭,只能分层降低其影响,数据库唯一索引是最后一道不可绕过的硬约束。

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