3.2 Redis实战应用之限制用户访问频率

一、场景举例

我们日常上网冲浪的时候,常常会遇到这样的情景:

  • 多次输错登陆密码,再次尝试登录,页面提示需要输入正确的图形验证码
  • 某内容平台限定,每个账号单日可发布的文章数量不得超过规定上限
  • 采用短信验证码进行交互的场景,M分钟内请求的验证码次数过多,接下来的N分钟里会被拒绝请求,并提示"用户操作频繁,请稍后再试"

当网站的访问量突然很大的时候肯定会对服务器造成影响,甚至无法访问,如果是正常的访问那么很好说明业务量增大可以考虑系统的拓展,但是如果是搜索引擎爬虫频繁访问或是一些恶意访问,那这时候我们就应该限制这些访问的访问次数。redis刚好可以解决这个问题。

在这里插入图片描述

二、实现

1.方式一

限制每个用户每分钟最多只能访问100个页面。

实现思路:key使用有“rate.limiting:IP”,value使用数值,用户每次访问将value的值通过INCR命令自增1,如果自增后的值是1同时去设置过期时间为1分钟。这样用户每次访问的时候都会读取该键的值,如果超过100就表明该用户的访问频率超过了限制,需要提示用户稍后操作。且每分钟该键会被自动删除。所以下一分钟又会重新计算,这样就达到了限制访问频率的目的。

在这里插入图片描述
伪代码

String key = "rage.limiting:"+ip;
//判断key是否存在
int isExist=exists(key);
//key值存在
if(isExist == 1){
	//自增1
	int count=incr(key);
	if(count > 100){
		//超出限制
		log.info("访问频率超出限制,请稍后重试");
		return;
	}
}else{
	//key值不存在
	multi();//开启事务
	incr(key);//key不存在自增1 值为1
	expire(key,60);//设置过期时间
	exec();//提交事务
}

2.方式二:list

实际上,方式一有个问题:如果一个用户在第一分钟的最后一秒访问了99次,在下一分钟的第一秒访问了100次,那么就相当于在两秒访问了199次,这就与一分钟内最多访问100次相比差距比较大,尽管这种情况比较极端,但是仍然存在。所以如果要实现粒度更小的控制方式,精确到每分钟最多访问100次,那就需要使用到第二种方式。

方式二需要记录用户每次的访问时间,因此对于每个用户,用列表类型的键记录他最近100次访问的时间。如果键中的元素超过100个,就判断时间最早的元素距离现在的时间是否小于1分钟,如果是,则表示用户最近1分钟的访问次数超过100次,如果不是就将当前时间加入列表中,同时把最早的元素删除。
在这里插入图片描述
伪代码

String key= "rage.limiting:"+ip;
int listLength=llen(key);
if(listLength<100){
	lpush(key,new());
}else{
	long time=lindex(key,-1);
	if(now()-time < 60){
		log.info("超出了访问频率");
	}else{
		lpush(key,now);
		ltrim(key,0.9);
	}
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值