Redis 使用场景实战:缓存与限流

问题:如果有这样一个场景,对于同一个url请求,1分钟之内请求数达到10次就不允许请求?这样一个业务场景,你应该怎么设计?

这是一个典型的 限流(Rate Limiting) 场景。对于同一个 URL 请求,在 1 分钟之内请求超过 10 次就拒绝访问,属于 基于时间窗口的限流策略

✅ 一、整体设计思路

我们可以使用 Redis 来实现一个高效的限流器(Rate Limiter),利用其高性能读写和过期机制来记录每个客户端对某个 URL 的访问频率。

1. 基本逻辑

  • 对于每次请求,根据客户端标识(如 IP 或用户 ID)+ URL 构造一个 key。
  • 使用 Redis 的 INCR 命令对该 key 进行自增计数。
  • 如果是第一次访问,则设置该 key 的过期时间为 60 秒。
  • 判断当前值是否超过阈值(例如 10),如果超过则拒绝请求。

2. Redis 数据结构选择

  • 使用 String 类型 存储访问次数即可。
  • Redis 的 INCREXPIRE 命令天然支持原子操作,非常适合这种场景。

✅ 二、Redis Key 设计建议

rate_limit:{client_id}:{url_md5}  

示例:

rate_limit:192.168.1.1:/api/user/info
rate_limit:user_123:/api/order/detail

说明:URL 可能比较长,可以使用 MD5 或 SHA1 缩短长度,避免 key 过长影响性能。

✅ 三、具体实现步骤(伪代码)

🧠 核心逻辑(Lua 脚本推荐)

为了保证“判断 + 自增 + 设置过期”的原子性,建议使用 Lua 脚本来完成整个流程:

-- rate_limit.lua
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local expire_time = tonumber(ARGV[2])

local current = redis.call('get', key)
if current and tonumber(current) >= limit then
    return 0 -- 超出限制
elseif current then
    redis.call('incr', key)
else
    redis.call('setex', key, expire_time, 1)
end
return 1 -- 允许访问

🧪 调用方式(以 Redis CLI 为例)

EVAL "local key=KEYS[1]; local limit=tonumber(ARGV[1]); local expire_time=tonumber(ARGV[2]); local current=redis.call('get', key); if current and tonumber(current)>=limit then return 0; elseif current then redis.call('incr', key); else redis.call('setex', key, expire_time, 1); end; return 1;" 1 rate_limit:192.168.1.1:/api/user/info 10 60

返回值含义:

  • 1:允许访问
  • 0:超出限制,拒绝访问

✅ 四、系统集成建议

1. 在网关层或中间件中拦截请求

  • 在 Nginx/OpenResty、Spring Cloud Gateway、Zuul、Kong 等网关中嵌入限流逻辑。
  • 可以结合 Lua 脚本直接调用 Redis 实现高效限流。

2. 客户端标识建议

  • IP 地址:适用于无登录态的公共接口。
  • 用户ID(uid):适用于已登录用户。
  • API Key / Token:更精确控制访问权限。

3. 日志与监控

  • 记录被限流的请求日志。
  • 结合 Prometheus + Grafana 监控限流情况。
  • 配置告警机制,防止恶意攻击。

✅ 五、扩展功能(可选)

功能描述
滑动窗口限流更精确地统计最近 60 秒内的请求数(比固定窗口更平滑)
动态配置限流规则支持不同用户/角色有不同的限流阈值
黑名单机制多次触发限流的用户加入黑名单
集群限流多节点共享限流状态,适合微服务架构

✅ 六、注意事项

问题解决方案
Redis 单点故障使用 Redis Cluster 或哨兵模式保障高可用
键名冲突加命名空间前缀,如 ratelimit:
内存占用过高合理设置 TTL,定期清理冷数据
Lua 脚本执行超时控制脚本复杂度,不要做太多计算
误限流区分真实用户和爬虫,必要时增加 CAPTCHA 验证

✅ 七、总结

项目推荐方案
数据存储Redis String
原子操作Lua 脚本封装 INCR + EXPIRE
Key 设计rate_limit:{client_id}:{url}
部署位置API 网关或业务层前置中间件
扩展能力支持滑动窗口、黑名单、动态规则等
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值