大家好,我是苏三。

今天我们不聊风花雪月,只讲这个让无数开发者夜不能寐的终极命题:当恶意流量如海啸般扑来,如何守住你的系统防线?

有些小伙伴在工作中可能经历过接口被刷的噩梦,但百万QPS量级的攻击完全是另一个维度的战争。

今天这篇文章跟大家一起聊聊接口被刷百万QPS,如何防御,希望对你会有所帮助。

为什么百万QPS如此致命?

用一张图给解释一下百万QPS的危害:

攻击者三大核心武器:

  1. IP海洋战术:10万+代理IP池动态轮转,传统IP限流失效。
  2. 设备克隆技术:伪造浏览器指纹,模拟真实设备行为。
  3. 协议级精准攻击:精心构造的HTTP请求,绕过基础WAF规则。

系统崩溃的致命链反应:

  • 线程池100%占用 → 新请求排队超时
  • 数据库连接耗尽 → SQL执行阻塞
  • Redis响应飙升 → 缓存穿透雪崩
  • 微服务连环熔断 → 服务不可用

那么,我们该如何防御呢?

第一道防线:基础限流与熔断

1. 网关层限流

我们需要在网关层做限流,目前主流的解决方案是:Nginx + Lua。

下面是Nginx的限流配置:

location /api/payment {
access_by_lua_block {
local limiter = require "resty.limit.req"
-- 令牌桶配置:1000QPS + 2000突发容量
local lim, err = limiter.new("payment_limit", 1000, 2000)
if not lim then
ngx.log(ngx.ERR, "限流器初始化失败: ", err)
return ngx.exit(500)
end -- 基于客户端IP限流
local key = ngx.var.remote_addr
local delay, err = lim:incoming(key, true) if not delay then
if err == "rejected" then
-- 返回429状态码+JSON错误信息
ngx.header.content_type = "application/json"
ngx.status = 429
ngx.say([[{"code":429,"msg":"请求过于频繁"}]])
return ngx.exit(429)
end
ngx.log(ngx.ERR, "限流错误: ", err)
return ngx.exit(500)
end
}
}

代码解析:

  1. 使用OpenResty的lua-resty-limit-req模块
  2. 令牌桶算法:1000QPS常规流量 + 2000突发流量缓冲
  3. 基于客户端IP维度限流
  4. 超出限制返回429状态码和JSON格式错误

2. 分布式熔断

面对大流量时,我们需要增加分布式熔断机制,比如使用Sentinel集群流控。

下面是Sentinel集群的流控配置:

public class SentinelConfig {
@PostConstruct
public void initFlowRules() {
// 创建集群流控规则
ClusterFlowRule rule = new ClusterFlowRule();
rule.setResource("createOrder"); // 受保护资源
rule.setGrade(RuleConstant.FLOW_GRADE_QPS); // QPS限流
rule.setCount(50000); // 集群阈值5万QPS
rule.setClusterMode(true); // 开启集群模式
rule.setClusterConfig(new ClusterRuleConfig()
.setFlowId(123) // 全局唯一ID
.setThresholdType(1) // 全局阈值
); // 注册规则
ClusterFlowRuleManager.loadRules(Collections.singletonList(rule));
}
}

流程图如下:

实现原理:

  1. Token Server集中管理全集群流量配额
  2. 网关节点实时向Token Server申请令牌
  3. 当集群总QPS超过阈值时,按比例限制各节点流量
  4. 避免单节点限流导致的集群流量不均衡问题

第二道防线:设备指纹与行为分析

1. 浏览器指纹生成

前端可以在浏览器上生成指纹,即使客户端IP换了,但相同设备的指纹还是一样的。

前端设备指纹生成方案,这里使用了Canvas+WebGL。

// 前端设备指纹生成方案
function generateDeviceFingerprint() {
// 1. 获取基础设备信息
const baseInfo = [
navigator.userAgent,
navigator.platform,
screen.width + 'x' + screen.height,
navigator.language
].join('|'); // 2. 生成Canvas指纹
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#f60';
ctx.fillRect(0, 0, 100, 30);
ctx.fillStyle = '#069';
ctx.font = '16px Arial';
ctx.fillText('防御即艺术', 10, 20);
const canvasData = canvas.toDataURL(); // 3. 生成WebGL指纹
const gl = canvas.getContext('webgl');
const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
const renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL); // 4. 组合生成最终指纹
const fingerprint = md5(baseInfo + canvasData + renderer);
return fingerprint;
}

指纹特性分析:

  • 稳定性:相同设备多次生成一致性 > 98%
  • 唯一性:不同设备碰撞概率 < 0.1%
  • 隐蔽性:用户无感知,无法简单清除

2. 行为分析模型

我们还可以分析用户的行为。

使用下面的鼠标行为分析引擎:

import numpy as np

def analyze_mouse_behavior(move_events):
"""
分析鼠标移动行为特征
:param move_events: 鼠标移动事件列表 [{'x':100, 'y':200, 't':1680000000}, ...]
:return: 异常概率(0-1)
"""
# 1. 计算移动速度序列
speeds = []
for i in range(1, len(move_events)):
prev = move_events[i-1]
curr = move_events[i]
dx = curr['x'] - prev['x']
dy = curr['y'] - prev['y']
distance = (dx**2 + dy**2) ** 0.5
time_diff = curr['t'] - prev['t']
# 防止除零
speed = distance / max(0.001, time_diff)
speeds.append(speed) # 2. 计算加速度变化
accelerations = []
for i in range(1, len(speeds)):
acc = speeds[i] - speeds[i-1]
accelerations.append(acc) # 3. 提取关键特征
features = {
'speed_mean': np.mean(speeds),
'speed_std': np.std(speeds),
'acc_max': max(accelerations),
'acc_std': np.std(accelerations),
'linearity': calc_linearity(move_events)
} # 4. 使用预训练模型预测
return risk_model.predict([features])

行为特征维度:

  1. 移动速度:机器人速度恒定,真人波动大
  2. 加速度:机器人加速度变化呈锯齿状
  3. 移动轨迹线性度:机器人多为直线运动
  4. 操作间隔:机器人操作间隔高度一致

第三道防线:动态规则引擎

1. 实时规则配置

我们还可以使用动态规则引擎(比如:Drools引擎),可以配置风控规则。

Drools风控规则示例:

rule "高频访问敏感接口"
// 规则元数据
salience 100 // 优先级
no-loop true // 防止规则循环触发 // 条件部分
when
$req : Request(
path == "/api/coupon/acquire", // 敏感接口
$uid : userId != null, // 登录用户
$ip : clientIp
) // 统计同一用户10秒内请求次数
accumulate(
Request(
userId == $uid,
path == "/api/coupon/acquire",
this != $req, // 排除当前请求
$ts : timestamp
);
$count : count($ts),
$minTime : min($ts),
$maxTime : max($ts)
) // 判断条件:10秒内超过30次请求
eval($count > 30 && ($maxTime - $minTime) < 10000)
then
// 执行动作:阻断并记录
insert(new BlockEvent($uid, $ip, "高频领券"));
$req.setBlock(true);
end

规则引擎优势:

  • 实时生效:新规则秒级推送
  • 复杂条件:支持多维度联合判断
  • 动态更新:无需重启服务

2. 多维关联分析模型

我们需要建立一套多维关联分析模型:

使用风险评分机制。

评分模型公式:

风险分 =
IP风险权重 × IP评分 +
设备风险权重 × 设备评分 +
行为异常权重 × 行为异常度 +
历史画像权重 × 历史风险值

终极防御架构

下面用用一张图总结一下百万QPS防御的架构体系:

核心组件解析:

  1. 流量清洗层(CDN)

    • 过滤静态资源请求
    • 吸收70%以上流量冲击
  2. 安全防护层(网关集群)

    • 设备指纹生成:标记每个请求源
    • 分布式限流:集群级QPS控制
    • 规则引擎:实时判断风险
  3. 实时风控层(Flink计算)

// Flink实时风控处理
riskStream
.keyBy(req => req.getDeviceId()) // 按设备ID分组
.timeWindow(Time.seconds(10)) // 10秒滚动窗口
.aggregate(new RiskAggregator) // 聚合风险指标
.map(riskData => {
val score = riskModel.predict(riskData)
if(score > RISK_THRESHOLD) {
// 高风险请求阻断
blockRequest(riskData.getRequestId())
}
})
  1. 数据支撑层

    • Redis:存储实时风险画像
    • Flink:计算行为特征指标
    • 规则管理台:动态调整策略

血泪教训

1. IP白名单的陷阱

场景:将合作方IP加入白名单

灾难:攻击者入侵合作方服务器发起攻击

解决方案

使用设备指纹校验和行为分析。

2. 限流阈值静态设置的灾难

场景:设置固定5000QPS阈值

问题:大促时正常流量超阈值被误杀

优化方案

// 动态阈值调整算法
public class DynamicThreshold {
// 基于历史流量自动调整
public static int calculateThreshold(String api) {
// 1. 获取上周同时段流量
double base = getHistoricalQps(api);
// 2. 考虑当日增长系数
double growth = getGrowthFactor();
// 3. 保留20%安全余量
return (int)(base * growth * 0.8);
}
}

3. 忽略带宽成本

教训:10Gbps流量攻击导致月度预算超支200%

应对策略

  • 前置CDN吸收静态流量
  • 配置云厂商DDoS防护服务
  • 设置带宽自动熔断机制

真正的防御不是让攻击无法发生,而是让攻击者付出十倍代价却一无所获。当你的防御成本低于对手的攻击成本时,战争就结束了。

最后说一句(求关注,别白嫖我)

如果这篇文章对您有所帮助,或者有所启发的话,帮忙关注一下我的同名公众号:苏三说技术,我的所有文章都会在公众号上首发,您的支持是我坚持写作最大的动力。

求一键三连:点赞、转发、在看。

关注公众号:【苏三说技术】,在公众号中回复:进大厂,可以免费获取我最近整理的10万字的面试宝典,好多小伙伴靠这个宝典拿到了多家大厂的offer。

接口被刷百万QPS,怎么防?的更多相关文章

  1. 12306抢票带来的启示:看我如何用Go实现百万QPS的秒杀系统

    本文为开源实验性工程:“github.com/GuoZhaoran/spikeSystem”的配套文章,原作者:“绘你一世倾城”,现为:猎豹移动php开发工程师,感谢原作者的技术分享. 1.引言 Go ...

  2. Nginx 单机百万QPS环境搭建

    一.背景 最近公司在做一些物联网产品,物物通信用的是MQTT协议,内部权限与内部关系等业务逻辑准备用HTTP实现.leader要求在本地测试中要模拟出百万用户同时在线的需求.虽然该产品最后不一定有这么 ...

  3. 一次接口压力测试qps极低原因分析及解决过程

    一次接口压力测试qps极低原因分析及解决过程 9-2日在做内部的性能测试相关培训时,发现注册接口压力测试qps极低(20左右),这个性能指标远不能达到上线标准 ,经过一系列调试,最后定位 98%的时间 ...

  4. “12306”是如何支撑百万QPS的?

    来源:掘金 作者:绘你一世倾城 链接:https://juejin.im/post/5d84e21f6fb9a06ac8248149 秒杀系统的艺术 12306抢票,极限并发带来的思考? 每到节假日期 ...

  5. 一种简单的REST API接口加密实现,只允许自己的产品调用后台,防止接口被刷

    在项目上线后,后台接口很容易通过抓包工具看到, 难免被人为构造恶意请求攻击我们的系统,相信大家都或多或少都遇到过短信验证码被刷.疯狂留言灌水.数据被恶意爬取等问题,这种直接抓接口然后写个循环调用的行为 ...

  6. spring boot 对某个接口进行次数限制,防刷。简易版。demo。

    一般的项目 如果没有做防刷 容易被人爆接口 或者就是说没有做token防刷过滤. 容易被人用正常的token刷接口.有些token非一次性. 用户登录之后生成token会有一个过期时间,但一般没有做频 ...

  7. WebApi接口安全性 接口权限调用、参数防篡改防止恶意调用

    背景介绍 最近使用WebApi开发一套对外接口,主要是数据的外送以及结果回传,接口没什么难度,采用WebApi+EF的架构简单创建一个模板工程,使用template生成一套WebApi接口,去掉put ...

  8. 如何写出安全的API接口?接口参数加密签名设计思路

    开发中经常用到接口,尤其是在面向服务的soa架构中,数据交互全是用的接口. 几年以前我认为,我写个接口,不向任何人告知我的接口地址,我的接口就是安全的,现在回想真是too young,too simp ...

  9. 【阿里聚安全·安全周刊】女主换脸人工合成小电影|伊朗间谍APP苹果安卓皆中招

    本周的七个关键词: 人工智能 丨 HTTP链接=不安全链接 丨  滑动验证码 丨 伊朗间谍APP 丨 加密挖矿 丨  Android应用测试速查表 丨 黑客销售签名证书 -1-   [人工智能]女主换 ...

  10. 朱晔的互联网架构实践心得S1E9:架构评审一百问和设计文档五要素

    朱晔的互联网架构实践心得S1E9:架构评审一百问和设计文档五要素 [下载文本PDF进行阅读] 本文我会来说说我认为架构评审中应该看的一些点,以及我写设计文档的一些心得.助你在架构评审中过五关斩六将,助 ...

随机推荐

  1. Django实战项目-学习任务系统-用户管理

    接着上期代码框架,开发第6个功能,用户管理,查看用户信息和学生用户属性值,尤其是总积分值,还可以查看积分流水明细,完成任务奖励积分,兑换物品消耗积分. 第一步:编写第6个功能-用户管理 1,编辑模型文 ...

  2. 如何在 PostgreSQL 中运行 TLS 回归测试

    概述 本文将分享一个简单的步骤,介绍如何在 PostgreSQL 中运行 SSL/TLS 回归测试. Postgres 回归测试 每当我们想要添加新功能或进行修复时,都应该运行 PostgreSQL ...

  3. PDA自带有红外扫描头,不用点击焦点就能超高速超精准的扫条码、扫二维码

    参考牛人DelphiTeacher的<PDA扫码?不要慌,只要20行代码!> 摘要: 实现监听器接口 然后在系统中注册该监听器,注册时指定只接收名称为com.kte.scan.result ...

  4. 第一次3D打印,一个简单的小方块(rhino)

    一.建模 打开犀牛,我们选择立方体 我们点击上册的中心点 输入0,然后回车0 而后我们输长度:10,回车确认 同样的,宽度10 高度同样是10 回车确认后,我们得到一个正方形 二.导出模型 我们选择文 ...

  5. 将Particle转成UGUI

    在unity官方论坛看到的一个解决方案,可以将Particle直接转换成CanvasRenderer元素显示.新建一个UIParticleSystem.cs脚本,将以下代码复制进去: using Un ...

  6. SynchronousQueue底层实现原理剖

    一.SynchronousQueue底层实现原理剖 SynchronousQueue(同步移交队列),队列长度为0.作用就是一个线程往队列放数据的时候,必须等待另一个线程从队列中取走数据.同样,从队列 ...

  7. 康谋分享 | 3DGS:革新自动驾驶仿真场景重建的关键技术

    登录后复制 随着自动驾驶技术的迅猛发展,构建高保真.动态的仿真场景成为了行业的迫切需求.传统的三维重建方法在处理复杂场景时常常面临效率和精度的挑战.在此背景下,3D高斯点阵渲染(3DGS)技术应运而生 ...

  8. 在鸿蒙NEXT中开发一个2048小游戏

    本项目是基于api12开发的2048游戏,游戏的逻辑是当用户向某个方向滑动时,将该方向相邻且相等的数字相加,同时在空白区域的随机位置生成一个随机数字.游戏中的数字越大,分数越高. 首先,游戏的界面布局 ...

  9. vue3 基础-补充 ref & provide-inject

    本篇主要对一些被以前内容(渲染, 传值) 等忽略的几个常用小技巧进行补充说明啦. v-once 即对某个dom节点生效, 其会限定只会渲染一次, 不论数据是如何的变化, 演示如下: <!DOCT ...

  10. PyYaml简单学习

    YAML是一种轻型的配置文件的语言,远比JSON格式方便,方便人类读写,它通过缩进来表示结构,很具有Python风格. 安装:pip insall pyyaml YAML语法 文档 YAML数据流是0 ...