秒杀系统最怕的其实不只是“流量大”。

正常用户再多,至少大家都是:

打开页面
↓
看商品
↓
点抢购
↓
提交订单

黄牛脚本就不一样了。

可能在秒杀开始的一瞬间:

100个账号
1000个请求
几十台代理机器

同时打进来。

如果系统只遵循:

谁请求先到,库存就给谁。

最后很可能出现一种很尴尬的结果:

服务器扛住了,商品却全被脚本抢走了。

所以真正的秒杀系统,除了抗高并发,还必须解决另一个问题:

这个请求到底像不像一个正常用户?


一、系统其实并不能真正知道“你是不是人”

这是理解秒杀风控最重要的一点。

服务端收到一个请求:

POST /seckill

它看到的只是一些数据:

userId
IP
Cookie
Token
设备信息
请求时间
行为记录

服务器并没有办法隔着网络看见:

“电脑前面坐的是张三,还是一段 Python 代码。”

所以真正的实现方式并不是:

真人 → 放行
机器人 → 拦截

而是:

收集行为特征
↓
计算风险
↓
低风险放行
中风险验证
高风险拦截

也就是说:

秒杀反黄牛,本质上是风险识别,而不是机器识别。


二、最简单的一层:请求频率

假设正常用户抢一个商品。

可能是:

10:00:00.123  点击抢购
10:00:01.350  网络重试一次

但某个账号出现:

10:00:00.001
10:00:00.006
10:00:00.011
10:00:00.016
10:00:00.021

5毫秒一个请求。

基本就不用研究他的鼠标轨迹了。

人类正常情况下很难做到这种频率。

因此第一层通常就是:

IP限流
+
账号限流
+
设备限流

例如:

同一账号
1秒最多3次

同一设备
1秒最多5次

超过直接拒绝。

但只靠 IP 不够。

因为黄牛完全可以准备:

代理IP A
代理IP B
代理IP C
代理IP D
...

所以真正的风控不会只盯着一个 IP。


三、为什么还需要“设备指纹”?

假设一个黄牛控制了100个账号。

表面上:

账号不同
IP不同
手机号不同

看起来像100个人。

但仔细一看:

浏览器版本相同
屏幕分辨率相同
字体环境相同
操作系统相同
设备参数高度一致

甚至大量账号都来自同一种运行环境。

这时候系统就可以尝试生成:

Device Fingerprint

设备指纹。

它不一定是一个真实硬件序列号,而是根据多种客户端特征组合出的设备标识。

于是原来看到的是:

账号A
账号B
账号C
账号D

进一步分析可能发现:

        ┌→账号A
设备X ──┼→账号B
        ├→账号C
        └→账号D

这就开始可疑了。

所以风控经常不是问:

这个账号有没有问题?

而是问:

这些账号之间是不是存在异常关联?


四、真正厉害的是行为识别

脚本最容易暴露的地方其实不是“速度快”。

而是:

太标准了。

正常用户的行为通常有随机性。

比如:

进入页面
↓
停留2.3秒
↓
滑一下页面
↓
看商品
↓
点击抢购

另一个人可能是:

进入页面
↓
停留5秒
↓
点击规则
↓
返回
↓
抢购

人类行为天然有噪声。

脚本则容易变成:

请求页面
100ms
请求接口
100ms
请求下单
100ms

1000个账号都是:

100ms
100ms
100ms

这反而非常不自然。

所以风控系统可以统计:

页面停留时间
点击间隔
请求间隔
操作路径
失败重试频率
请求时间分布

然后判断:

这组行为到底像不像正常用户。


五、一个特别形象的例子

假设10点整开始抢茅台。

真实用户的请求时间可能是:

10:00:00.128
10:00:00.417
10:00:01.032
10:00:01.784

分布比较散。

某批异常账号却全部是:

账号A  10:00:00.001
账号B  10:00:00.001
账号C  10:00:00.002
账号D  10:00:00.001
账号E  10:00:00.002

如果有几百个账号都出现这种情况,就很值得怀疑。

因为它们很可能不是几百个人同时练成了“毫秒级手速”。

更可能是:

同一套程序在统一调度。

所以风控真正找的是:

异常的规律性。


六、账号本身也有“画像”

再往下一层,可以看账号历史。

比如正常用户:

注册半年
有浏览记录
有正常订单
有地址
偶尔参加活动

某个账号:

昨天注册
没有任何浏览记录
没有历史订单
今天第一次登录
秒杀前1分钟上线
10点整精准请求
抢完立即退出

风险显然完全不一样。

所以系统可以给账号建立一些特征:

账号年龄
历史订单数
登录频率
收货地址
支付信息
活动参与频率
退款率
设备更换频率

最后形成:

User Risk Score

比如:

正常老用户        +0

新注册账号        +10

频繁切换IP        +20

多个账号同设备    +30

毫秒级高频请求    +40

假设:

Risk Score < 30
→ 正常放行

30 ~ 70
→ 增加验证

> 70
→ 拒绝秒杀

真实系统当然会复杂很多,但底层思想基本就是这样。


七、验证码为什么不能一上来就给所有人?

很多系统想到防机器人,第一反应就是:

上验证码。

例如:

滑块
图片验证码
短信验证

确实有用。

但秒杀系统有一个特殊问题:

正常用户本来就很多。

如果100万人全部先做验证码:

用户体验下降
+
验证码服务压力暴涨
+
正常用户抱怨

所以更合理的是:

低风险用户
→ 直接通过

可疑用户
→ 滑块验证

高风险用户
→ 更强验证或者直接拒绝

这叫:

分级风控。

不是所有人都接受同样的验证成本。


八、为什么秒杀接口不能直接暴露?

假设页面里永远写死:

POST /api/seckill/10001

那么脚本根本不用打开页面。

它可以直接:

定时到10:00
↓
狂刷接口

因此实际设计中经常会增加一个“资格获取”过程。

例如:

进入活动
↓
完成必要校验
↓
获取短期秒杀资格
↓
携带资格访问下单接口

资格可以有:

用户绑定
商品绑定
过期时间
签名
一次性状态

服务端再验证:

资格是否合法?
是不是这个用户的?
是不是这个商品的?
有没有过期?
有没有重复使用?

这并不能让脚本彻底消失。

但它能把:

知道接口地址
=
可以直接抢

变成:

必须经过前面的业务链路
↓
才能获得下单资格

攻击成本会高很多。


九、为什么一定要多层拦截?

因为任何单一规则都容易误伤或者被绕过去。

只限制 IP:

换代理

只限制账号:

准备大量账号

只看设备:

伪造设备环境

只用验证码:

可能被打码平台或自动化识别绕过

所以真正有效的系统一般是:

CDN / WAF
        ↓
IP和网络层风控
        ↓
账号限流
        ↓
设备指纹
        ↓
行为分析
        ↓
风险评分
        ↓
必要时验证码
        ↓
秒杀资格校验
        ↓
Redis库存
        ↓
MQ
        ↓
创建订单

黄牛每突破一层,都要付出新的成本。

反黄牛真正追求的也不是:

世界上任何脚本都进不来。

这个目标基本不现实。

更实际的是:

让批量作弊的成本高到没有收益。


十、风控为什么不能写死成一堆 if?

最简单的系统可能这样写:

if (requestCount > 10) {
    reject();
}

if (accountAge < 1) {
    reject();
}

if (deviceUserCount > 5) {
    reject();
}

刚开始能用。

规则越来越多以后,很快就会变成:

几十个if
+
规则互相冲突
+
误杀越来越严重

所以成熟一点的做法通常会抽象成:

特征
↓
风险规则 / 风控模型
↓
Risk Score
↓
决策

例如:

risk =
    请求频率 × 权重
  + 设备异常 × 权重
  + 账号异常 × 权重
  + 行为异常 × 权重

然后根据风险等级采取不同措施。

这样以后发现新的黄牛模式,只需要增加:

新的特征
或者
新的规则

不需要把整个秒杀业务重写一遍。


总结

秒杀系统想区分真实用户和黄牛脚本,底层并没有一个神奇的:

isHuman()

真正做的是不断收集信号:

这个账号正常吗?
这个设备正常吗?
请求频率正常吗?
行为路径正常吗?
这些账号有没有关联?
请求时间是不是过于规律?

然后:

多维特征
↓
风险评分
↓
分级处理

所以反黄牛最核心的思想不是:

识别出所有机器人。

而是:

识别“正常人很少会出现,但批量自动化工具经常出现”的行为模式。

最后再通过:

限流 + 设备 + 账号 + 行为 + 验证 + 秒杀资格

层层提高作弊成本。

这也是秒杀风控最重要的底层逻辑:

真正有效的反黄牛,不是筑一道绝对攻不破的墙,而是让批量作弊变得越来越贵。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐