【JAVA架构师成长之路】【电商系统实战】第11集:秒杀系统防刷实战(验证码 + 用户行为黑名单)
30分钟课程:秒杀系统防刷实战(验证码 + 用户行为黑名单)
课程目标
- 掌握验证码生成与校验技术,拦截机器人请求。
- 基于 Redis 实现用户行为分析,动态识别并封禁恶意用户。
- 设计高可用的防刷策略,保障秒杀活动公平性。
课程内容与时间分配
0~5分钟:课程概述
业务场景与挑战
- 机器人刷单:脚本高频请求抢占库存,正常用户无法参与。
- 恶意用户:同一用户多次违规操作(如频繁点击、多账号参与)。
- 核心目标:
- 人机识别:通过验证码区分真人用户与机器人。
- 行为分析:实时监控用户行为,识别异常模式。
技术方案
- 验证码:图片验证码(Kaptcha)或滑动拼图验证。
- 用户行为分析:Redis 记录请求频率、IP、设备指纹。
- 黑名单机制:自动封禁异常用户(IP、UserID、设备)。
5~10分钟:技术难点与核心问题
- 验证码安全性
- 如何防止验证码被OCR识别或接口绕过?
- 实时行为统计
- 高并发下如何高效记录用户行为(如QPS >10万)?
- 动态封禁策略
- 如何根据行为数据动态调整封禁规则(如5秒内10次请求封禁)?
- 用户体验平衡
- 如何减少对正常用户的干扰(如首次请求免验证)?
10~25分钟:解决方案与代码实战
1. 验证码集成(10~15分钟)
依赖配置(Spring Boot + Kaptcha)
<dependency>
<groupId>com.github.axet</groupId>
<artifactId>kaptcha</artifactId>
<version>0.0.9</version>
</dependency>
生成验证码接口
@RestController
public class CaptchaController {
@Autowired
private Producer kaptchaProducer;
@GetMapping("/captcha")
public void generateCaptcha(HttpServletResponse response, HttpSession session) throws IOException {
// 生成验证码文本和图片
String text = kaptchaProducer.createText();
BufferedImage image = kaptchaProducer.createImage(text);
// 存储验证码文本到Session(或Redis)
session.setAttribute("captcha", text);
// 返回图片流
response.setContentType("image/png");
OutputStream os = response.getOutputStream();
ImageIO.write(image, "png", os);
os.flush();
}
}
校验验证码逻辑
public boolean verifyCaptcha(String userInput, HttpSession session) {
String captcha = (String) session.getAttribute("captcha");
return userInput != null && userInput.equalsIgnoreCase(captcha);
}
2. 用户行为分析与黑名单(15~25分钟)
Redis数据结构设计
- 用户行为记录:Hash 存储用户ID/IP的请求计数和时间戳。
- Key:
behavior:user:{userId}
, Field:count
,lastTime
- Key:
- 黑名单:Set 存储封禁的IP/UserID。
- Key:
blacklist:ip
, Value: 封禁IP列表
- Key:
行为统计Lua脚本(原子递增+过期时间)
-- KEYS[1]: 用户行为键(如 behavior:user:1001)
-- ARGV[1]: 过期时间(秒)
local count = redis.call('HINCRBY', KEYS[1], 'count', 1)
redis.call('HSET', KEYS[1], 'lastTime', ARGV[2])
redis.call('EXPIRE', KEYS[1], ARGV[1])
return count
Java代码:记录行为并检查黑名单
@Service
public class BehaviorAnalysisService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
private static final String BEHAVIOR_KEY_PREFIX = "behavior:user:";
private static final String BLACKLIST_KEY = "blacklist:ip";
// 记录用户行为
public long recordUserBehavior(String userId, String ip) {
String key = BEHAVIOR_KEY_PREFIX + userId;
String luaScript = "上述 Lua 脚本内容";
DefaultRedisScript<Long> script = new DefaultRedisScript<>(luaScript, Long.class);
return redisTemplate.execute(script, Collections.singletonList(key), "300", String.valueOf(System.currentTimeMillis()));
}
// 检查是否在黑名单
public boolean isBlacklisted(String ip) {
return redisTemplate.opsForSet().isMember(BLACKLIST_KEY, ip);
}
// 添加黑名单
public void addToBlacklist(String ip, int expireSeconds) {
redisTemplate.opsForSet().add(BLACKLIST_KEY, ip);
redisTemplate.expire(BLACKLIST_KEY, expireSeconds, TimeUnit.SECONDS);
}
}
封禁策略逻辑(示例)
public void checkAndBlockUser(String userId, String ip) {
if (isBlacklisted(ip)) {
throw new RuntimeException("IP已被封禁");
}
long count = recordUserBehavior(userId, ip);
if (count > 10) { // 10秒内超过10次请求
addToBlacklist(ip, 3600); // 封禁1小时
throw new RuntimeException("请求过于频繁,已被限制");
}
}
25~30分钟:练习与拓展
练习题目
- 动态封禁规则配置
- 要求:从数据库读取封禁阈值(如5秒内5次),实现动态规则加载。
- 设备指纹生成
- 任务:根据用户浏览器指纹(UserAgent+IP)生成唯一标识,增强黑名单精度。
推荐拓展方向
- 机器学习模型
- 使用实时日志训练模型,自动识别异常行为模式(如Flink + TensorFlow)。
- 多级验证策略
- 首次请求免验证,后续触发滑块验证或短信验证码。
- 分布式限流
- 结合 Nginx 层限流(漏桶算法)与用户行为分析,多层防护。
课程总结
- 验证码核心:生成与校验分离,避免接口被暴力破解。
- 行为分析关键设计:
- 原子计数:Lua 脚本保证高并发下的计数准确性。
- 动态封禁:基于阈值自动触发黑名单。
- 多维度标识:IP、UserID、设备指纹联合分析。
- 适用场景:秒杀、抽奖、API接口防护等高频访问场景。
课后资源
- Kaptcha 文档:GitHub - Kaptcha
- Redis 行为分析案例:Redis Pattern: Rate Limiting
- 完整代码示例:GitHub - 防刷系统Demo