您现在的位置是:主页 > 数据库技术 > 数据库技术
Redis中如何实现限流策略
IDCBT2021-12-30【服务器技术】人已围观
简介这篇文章将为大家详细讲解有关Redis中如何实现限流策略,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。 一、简单的限流 基本原理 当系统处
这篇文章将为大家详细讲解有关Redis中如何实现限流策略,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。
一、简单的限流基本原理
当系统处理能力有限,如何组织计划外的请求对系统施压。首先我们先看下一些简单的限流策略,防止暴力攻击。比如要对IP访问,没5s只能访问10次,超过进行拦截。
如上图,一般使用滑动窗口来统计区间时间内的访问次数。
使用 zset
记录 IP
访问次数,每个 IP
通过 key
保存下来,score
保存当前时间戳,value
唯一用时间戳或者UUID来实现
代码实现public class RedisLimiterTest {
private Jedis jedis;
public RedisLimiterTest(Jedis jedis) {
this.jedis = jedis;
}
/**
* @param ipAddress Ip地址
* @param period 特定的时间内,单位秒
* @param maxCount 最大允许的次数
* @return
*/
public boolean isIpLimit(String ipAddress, int period, int maxCount) {
String key = String.format("ip:%s", ipAddress);
// 毫秒时间戳
long currentTimeMillis = System.currentTimeMillis();
Pipeline pipe = jedis.pipelined();
// redis事务,保证原子性
pipe.multi();
// 存放数据,value 和 score 都使用毫秒时间戳
pipe.zadd(key, currentTimeMillis, "" + UUID.randomUUID());
// 移除窗口区间所有的元素
pipe.zremrangeByScore(key, 0, currentTimeMillis - period * 1000);
// 获取时间窗口内的行为数量
Response<Long> count = pipe.zcard(key);
// 设置 zset 过期时间,避免冷用户持续占用内存,这里宽限1s
pipe.expire(key, period + 1);
// 提交事务
pipe.exec();
pipe.close();
// 比较数量是否超标
return count.get() > maxCount;
}
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost", 6379);
RedisLimiterTest limiter = new RedisLimiterTest(jedis);
for (int i = 1; i <= 20; i++) {
// 验证IP 10秒钟之内只能访问5次
boolean isLimit = limiter.isIpLimit("222.73.55.22", 10, 5);
System.out.println("访问第" + i + "次, 结果:" + (isLimit ? "限制访问" : "允许访问"));
}
}
}
很赞哦! ()
标签:
很赞哦! ()