如果网站收到恶意攻击,网站访问频率可能在某个时间段特别高可能,影响网站性能,严重还能能导致往网站直接崩溃;网站的访问频率限制可以解决这个问题,
Redis实现限制访问频率
1:实现访问:
例如限制每个用户在一段事件内只能访问一定数量的次数如;一分钟只能访问100次,思路:key可以使用 "rete.limiting:ip",value 使用数值,用户每次访问将通过INCR命令自增1,如果自增后的值是1同时设置过期时间为1分钟,这样用户每次访问的时候都读取该键值,如果超过了100次,就表名访问超过了限制,需要提醒用户稍后访问,且该键值每分钟会自动删除,所以下一分钟有会重新计算,这样就达到了范文频率的目的。相关代码:
String key="rege.limiting:"+ip;
//判断key是否存在
int flag=exits(key);//key rate.limiting:192.162.177.128
if(flag==1){
//key 存在 自增
ing count=incr(key);
if(count>100){
//超时限制
log.info("访问频率超过了限制,稍后重试");
return ;
}
}else{
multi();//开启事务;
incr(key);//key不存在自增1,值为1;
expire(key,60);//设置过期时间
exec();//事物提交
}
实现方式二:
实现一些问题的时候还是有问题的,例如用户第一分钟的访问了99次,前面1秒访问了90次,然后用户后一秒访问而来99 次,然后下一分钟的第一秒有访问了90次,再后面的59秒访问了9次,这样上面的算法就是会有漏洞的:
解决方法:将上面案例中的100次调整为10次便于在次场景中描述,要精确的保证同一用户每分钟最多访问10次,需要将用户访问的事件记录下来,因此对每个用户我们使用List列表类型的键来记录他最近10次的访问时间,一旦键中元素超过了10个,就判断最早元素距离现在元素是否超过1分钟,如果表示用户最近1分钟访问次数超过了10次,就提醒稍后访问,如果不是就将现在的时间加入到队列中,同时将最早的元素删除。
代码:
String key = "rate.limiting:"+IP;
int listLength = llen(key);
if(listLength < 10){
lpush(key,new());
}else{
long time = lindex(key,-1);
if(now()-time < 60){
log.info("访问频率超过了限制,请稍后再试");
}else{
lpush(key,now);
ltrim(key,0,9);
}
}