1. 项目背景与核心挑战
某产业园区数字化平台近期频繁遭遇API接口恶意刷取攻击,主要表现为:
- 同一IP在极短时间内发起大量重复请求
- 攻击者使用脚本模拟正常业务流量
- 部分热点接口被集中攻击导致服务降级
我们采用Spring Boot + Redis + Sentinel技术栈构建了三重防护体系:
- Redis滑动窗口计数器实现基础频率控制
- Sentinel热点参数限流保护关键业务接口
- 动态规则引擎实现实时策略调整
这套组合方案上线后成功拦截了99%的恶意请求,核心业务接口的可用性从82%提升至99.9%。下面详细拆解实现方案。
2. 技术方案设计
2.1 整体架构设计
防护系统采用分层防御策略:
客户端请求 → API网关层 → 业务服务层 ↑ ↑ [限流防护] [熔断降级]关键组件分工:
- Spring Boot:作为基础框架提供RESTful接口
- Redis:存储滑动窗口计数数据
- Sentinel:实现热点参数限流和系统保护
2.2 Redis滑动窗口实现
2.2.1 算法原理
滑动窗口算法相比固定窗口能更精确控制单位时间请求量。我们采用60秒窗口分成6个格子(每格10秒),数据结构设计:
// Redis key设计 String key = "rate_limit:" + apiPath + ":" + clientIp; // Lua脚本实现原子操作 local current = redis.call('incr', KEYS[1]) if tonumber(current) == 1 then redis.call('expire', KEYS[1], ARGV[1]) end return current2.2.2 参数调优
经过压力测试确定的优化参数:
- 窗口大小:60秒(兼顾精度和性能)
- 子窗口数:6个(每10秒一个计数点)
- 最大请求数:根据接口重要性设置100-500次/分钟
注意:在集群环境下需要使用Redisson的RRateLimiter或自行实现分布式锁
2.3 Sentinel热点规则配置
2.3.1 热点参数识别
通过历史日志分析出需要特殊保护的参数:
// 示例:根据商品ID限流 @SentinelResource(value = "productDetail", blockHandler = "handleBlock") public Product getDetail(String productId) { //... }2.3.2 动态规则配置
通过Nacos实现规则热更新:
[ { "resource": "productDetail", "paramIdx": 0, "count": 50, "durationInSec": 1 } ]3. 核心实现细节
3.1 滑动窗口计数器实现
完整Java实现代码:
public boolean tryAcquire(String key, int limitCount, int windowSize) { long now = System.currentTimeMillis(); long windowStart = now - windowSize * 1000; // 使用Redis ZSET实现 String zkey = "rate:window:" + key; redisTemplate.opsForZSet().removeRangeByScore(zkey, 0, windowStart); long count = redisTemplate.opsForZSet().count(zkey, windowStart, now); if (count < limitCount) { redisTemplate.opsForZSet().add(zkey, UUID.randomUUID().toString(), now); return true; } return false; }3.2 Sentinel集成方案
3.2.1 Spring Boot配置
@Configuration public class SentinelConfig { @PostConstruct public void init() { // 注册通用降级处理器 WebCallbackManager.setUrlBlockHandler((req, resp, e) -> { resp.setContentType("application/json"); resp.getWriter().print("{\"code\":429,\"msg\":\"请求过于频繁\"}"); }); } }3.2.2 热点规则动态加载
@RestController @RequestMapping("/sentinel") public class SentinelRuleController { @Autowired private DynamicSentinelRuleService ruleService; @PostMapping("/rule") public String updateRule(@RequestBody FlowRule rule) { ruleService.publishRule(rule); return "success"; } }4. 性能优化与问题排查
4.1 Redis性能优化
实测数据对比:
| 优化措施 | QPS提升 | 内存消耗 |
|---|---|---|
| 原生incr | 12,000 | 低 |
| Lua脚本 | 8,500 | 低 |
| ZSET方案 | 5,200 | 较高 |
最终选择方案:
- 高频接口:使用incr+lua
- 精确控制:使用ZSET方案
4.2 常见问题处理
4.2.1 限流误判
现象:正常用户被拦截解决:
- 建立IP白名单机制
- 实施用户分级限流策略
- 添加验证码二次验证
4.2.2 Redis内存增长
现象:Redis内存持续增长解决:
# 设置自动过期 redis-cli config set maxmemory-policy allkeys-lru redis-cli config set maxmemory 2gb5. 防护效果验证
上线前后关键指标对比:
| 指标 | 防护前 | 防护后 |
|---|---|---|
| 恶意请求拦截率 | 23% | 99.2% |
| API平均响应时间 | 480ms | 210ms |
| 服务可用性 | 82% | 99.94% |
| Redis内存占用 | - | 1.2GB |
实际监控截图显示,攻击时段系统负载保持平稳:
[正常流量] ~~~~~~~~~ [攻击时段] |=======| (限流生效) [恢复后] ~~~~~~~~~6. 扩展优化方向
- 智能风控:结合机器学习识别异常模式
- 设备指纹:增强客户端识别能力
- 动态密钥:定期更换API访问凭证
- 多级缓存:减轻数据库压力
这套方案经过三个月的生产验证,在保证正常业务的前提下有效抵御了恶意请求。核心在于根据业务特点组合多种技术手段,而非依赖单一防护机制。