📖 模块简介
在金融业务、支付系统等高安全性场景下,防止恶意刷接口、撞库、爬虫等攻击至关重要。通过 Redis 的高性能计数器和灵活的数据结构,可以实现基于 IP、用户、设备 ID 的多维度行为限流,有效抵御各类高频攻击。本文介绍其原理、典型场景、Go 语言实现、常见问题与最佳实践。
🧠 基础原理
- 计数器限流:利用 Redis INCR/EXPIRE 组合,实现固定窗口限流(如每分钟最多 N 次)。
- 滑动窗口/漏桶/令牌桶:可用 Lua 脚本实现更精细的滑动窗口、漏桶、令牌桶等限流算法。
- 多维度限流:以 IP、用户 ID、设备 ID 等为 key 维度,分别计数,灵活组合防护。
- 原子性与高可用:所有操作在 Redis 端原子执行,适合高并发场景。
💼 金融业务应用场景
- 登录/注册接口防刷:对单 IP、单用户、单设备多维限流,防止撞库和恶意注册。
- 支付/提现频率控制:限制单用户、单设备在短时间内的高频操作,防止资金风险。
- API 接口防爬虫:对外开放接口按 IP、用户、设备限流,保护系统稳定。
- 营销活动防刷单:活动期间,防止同一用户或设备频繁参与。
💻 示例代码(Go + Redis)
1. 固定窗口限流(以 IP 为例,每分钟最多 10 次)
ip := "192.168.1.100"
key := fmt.Sprintf("limit:ip:%s:%d", ip, time.Now().Unix()/60) // 按分钟分片
limit := 10
cnt, err := rdb.Incr(ctx, key).Result()
if err != nil {
// Redis 异常处理
}
if cnt == 1 {
rdb.Expire(ctx, key, 61*time.Second) // 设置过期
}
if cnt > int64(limit) {
// 超过限制,拒绝请求
return errors.New("请求过于频繁,请稍后再试")
}
// 继续业务逻辑
2. 多维度限流(用户+设备)
userID := "u1001"
deviceID := "dev123"
key := fmt.Sprintf("limit:userdev:%s:%s:%d", userID, deviceID, time.Now().Unix()/60)
limit := 5
cnt, err := rdb.Incr(ctx, key).Result()
if cnt == 1 {
rdb.Expire(ctx, key, 61*time.Second)
}
if cnt > int64(limit) {
// 拒绝请求
}
🚨 常见问题与注意事项
- 分布式部署一致性:所有业务节点需共用同一 Redis,防止限流绕过。
- 高并发下的原子性:INCR/EXPIRE 需保证原子性,建议用 Lua 脚本封装。
- 滑动窗口实现复杂:如需更平滑限流,需用 Lua 实现滑动窗口算法。
- 误伤正常用户:阈值需结合业务实际,避免误伤。
- key 膨胀与内存管理:大量限流 key 需合理设置过期,防止内存膨胀。
✅ 最佳实践建议
- 多维度(IP、用户、设备)组合限流,提升安全性。
- 阈值设置结合业务实际,动态调整。
- 高并发场景建议用 Lua 脚本保证原子性。
- 定期监控限流 key 数量与内存占用。
- 结合黑名单、验证码等多重防护措施。