目前准备用redis实现分布式限流策略, 抛开那些redis插件,我觉得zset实现理论上可行, 具体逻辑可以是这样:
- 抽象限流逻辑: 针对某个action,需要在一段时间(即为窗口),只能容许N个操作
- redis伪代码
func increment(key, windowInSecond) {
Long 当时时间 = System.currentTimeMillis();
long maxScoreMs = 当时时间 - windowInSecond * 1000;
// 只留下滑动窗口的数据
redis.zremrangeByScore(key, 0, maxScoreMs);
// incre这一次的操作
redis.zadd(key, 当时时间, 当前时间 + 随机值);
}
func getCount(key) {
return redis.acard(key);
}
问题:
假设某个行为有大量的不同样本或者不同实例在调用, 也就是key不一样, 假设有百万以上,但是每个key的行为发生次数有限,例如就一次, 这个时候就会出现很大冷数据
处理该问题的方案:
- 窗口设置expire, 但是这个时候窗口策略就不是100%准确, 例如: 窗口即将过期发生操作行为N-1次, 窗口过期立刻新建又发生N-1次,这时候策略没有限流?
- 限流冷key被动删除, 但是我觉得这个策略太low了, 我为了限流还得写被动删除脚本.
想问下大家, 有没有更优的方案, 或者针对分布式限流, 有没有更好的策略
设置一个过期时间就行了。数据超过这个时间之后,Redis就会自动删除这些数据。或者弄一个定时任务,定一个时间清理窗口里的冷数据
可以看看 redis设计与实现这本书
思否往期相关回答:redis 遇到冷数据过多怎么办,怎么处理?