incr命令和expire命令的误区--举例每分钟访问次数限制

2024-09-04 00:18

本文主要是介绍incr命令和expire命令的误区--举例每分钟访问次数限制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

要实现的功能:限制用户的每分钟的访问次数

一个有严重bug的代码:每次访问来了,就执行代码块二,当第一次访问,就走else语句,设置当前用户的次数为1,且设置该key的有效期是一分钟。
在一分钟之内,第二次来访问了,就走if语句了,因为redis存在这个key了,就实现自增一,然后取出来判断是否超过了设定的阈值。逻辑上看似看似没什么问题。

代码块一:

Long maxAllowedTimes = 100L;
Long REQUEST_EXIT_MILLISECONDS = 60*1000L;
代码块二:
Jedis jedis = RedisUtils.getJedis();
String requestKey = Times + ":" + ID + ":" + getId();
if (jedis.exists(requestKey)) {//???jedis.incr(requestKey);String times = jedis.get(requestKey);if (StringUtil.strIsNotEmpty(times)){if (Long.parseLong(times) > maxAllowedTimes) {jedis.del(requestKey);return true;}}
} else {jedis.set(requestKey, "1");jedis.pexpire(requestKey,REQUEST_EXIT_MILLISECONDS);
}


实际上问题来了,maxAllowedTimes给设置成1000次,而实际上每分钟没有超过1000次的去访问数也能return true。
这TM设置的key的有效期没起到作用啊。。。各种讲道理讲不通,也是醉了。。。

其实不然,经过查资料发现:

Redis Incr 命令将 key 中储存的数字值增一,如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作,且将key的有效时间设置为长期有效。

耶,这么说就对了。其实,即使判断了key是否存在if (jedis.exists(requestKey)),也不能保证在执行jedis.incr(requestKey)自增的时候key是存在的。问题就出在这里。

就是这么巧,当三个问号“//???”这里时,恰好key到期了,从redis中删除了,然后继续执行jedis.incr(requestKey)自增,这时候,key的value等于1,且key是长期有效的。
所以当前用户不管何时每次访问的时候(只要redis不重启),key始终是存在的,这样就会一直自增,自增,自增到1000次。就这样bug就出现了。

解决方案:得对症下药啊

Jedis jedis = RedisUtils.getJedis();
String requestKey = Times + ":" + ID + ":" + getId();
jedis.incr(requestKey);//如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作,且将key的有效时间设置为长期有效.
String times = jedis.get(requestKey);
if("1".equals(times)){jedis.pexpire(requestKey,REQUEST_EXIT_MILLISECONDS);//如果是第一次访问,设置key的有效时间
} else if(StringUtils.isEmpty(times)){//如果key过期了,再incr(从第1次开始记录),再设置key的有效时间jedis.incr(requestKey);jedis.pexpire(requestKey,REQUEST_EXIT_MILLISECONDS);times = jedis.get(requestKey);
}
if (times != null && Long.parseLong(times) > maxAllowedTimes) {jedis.del(requestKey);return true;
}


至此,问题解决。
这里只是给出了一种“限制用户的每分钟的访问次数”的实现方案,应该还有其他更安全跟有效的实现方案。如有,请赐教,一起学习讨论。


另外:

Redis Incrby 命令将 key 中储存的数字加上指定的增量值,如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。

Redis Hincrby 命令用于为哈希表中的字段值加上指定增量值。
--------------------- 
作者:Joohong 
来源:CSDN 
原文:https://blog.csdn.net/jingzi123456789/article/details/80625930?utm_source=copy 
版权声明:本文为博主原创文章,转载请附上博文链接!

这篇关于incr命令和expire命令的误区--举例每分钟访问次数限制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1134457

相关文章

Linux使用dd命令来复制和转换数据的操作方法

《Linux使用dd命令来复制和转换数据的操作方法》Linux中的dd命令是一个功能强大的数据复制和转换实用程序,它以较低级别运行,通常用于创建可启动的USB驱动器、克隆磁盘和生成随机数据等任务,本文... 目录简介功能和能力语法常用选项示例用法基础用法创建可启动www.chinasem.cn的 USB 驱动

关于Maven生命周期相关命令演示

《关于Maven生命周期相关命令演示》Maven的生命周期分为Clean、Default和Site三个主要阶段,每个阶段包含多个关键步骤,如清理、编译、测试、打包等,通过执行相应的Maven命令,可以... 目录1. Maven 生命周期概述1.1 Clean Lifecycle1.2 Default Li

windows系统下shutdown重启关机命令超详细教程

《windows系统下shutdown重启关机命令超详细教程》shutdown命令是一个强大的工具,允许你通过命令行快速完成关机、重启或注销操作,本文将为你详细解析shutdown命令的使用方法,并提... 目录一、shutdown 命令简介二、shutdown 命令的基本用法三、远程关机与重启四、实际应用

Python 标准库time时间的访问和转换问题小结

《Python标准库time时间的访问和转换问题小结》time模块为Python提供了处理时间和日期的多种功能,适用于多种与时间相关的场景,包括获取当前时间、格式化时间、暂停程序执行、计算程序运行时... 目录模块介绍使用场景主要类主要函数 - time()- sleep()- localtime()- g

使用Python实现批量访问URL并解析XML响应功能

《使用Python实现批量访问URL并解析XML响应功能》在现代Web开发和数据抓取中,批量访问URL并解析响应内容是一个常见的需求,本文将详细介绍如何使用Python实现批量访问URL并解析XML响... 目录引言1. 背景与需求2. 工具方法实现2.1 单URL访问与解析代码实现代码说明2.2 示例调用

oracle中exists和not exists用法举例详解

《oracle中exists和notexists用法举例详解》:本文主要介绍oracle中exists和notexists用法的相关资料,EXISTS用于检测子查询是否返回任何行,而NOTE... 目录基本概念:举例语法pub_name总结 exists (sql 返回结果集为真)not exists (s

Java中switch-case结构的使用方法举例详解

《Java中switch-case结构的使用方法举例详解》:本文主要介绍Java中switch-case结构使用的相关资料,switch-case结构是Java中处理多个分支条件的一种有效方式,它... 目录前言一、switch-case结构的基本语法二、使用示例三、注意事项四、总结前言对于Java初学者

关于Java内存访问重排序的研究

《关于Java内存访问重排序的研究》文章主要介绍了重排序现象及其在多线程编程中的影响,包括内存可见性问题和Java内存模型中对重排序的规则... 目录什么是重排序重排序图解重排序实验as-if-serial语义内存访问重排序与内存可见性内存访问重排序与Java内存模型重排序示意表内存屏障内存屏障示意表Int

Linux使用nohup命令在后台运行脚本

《Linux使用nohup命令在后台运行脚本》在Linux或类Unix系统中,后台运行脚本是一项非常实用的技能,尤其适用于需要长时间运行的任务或服务,本文我们来看看如何使用nohup命令在后台... 目录nohup 命令简介基本用法输出重定向& 符号的作用后台进程的特点注意事项实际应用场景长时间运行的任务服

SpringBoot实现基于URL和IP的访问频率限制

《SpringBoot实现基于URL和IP的访问频率限制》在现代Web应用中,接口被恶意刷新或暴力请求是一种常见的攻击手段,为了保护系统资源,需要对接口的访问频率进行限制,下面我们就来看看如何使用... 目录1. 引言2. 项目依赖3. 配置 Redis4. 创建拦截器5. 注册拦截器6. 创建控制器8.