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

相关文章

安卓链接正常显示,ios#符被转义%23导致链接访问404

原因分析: url中含有特殊字符 中文未编码 都有可能导致URL转换失败,所以需要对url编码处理  如下: guard let allowUrl = webUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {return} 后面发现当url中有#号时,会被误伤转义为%23,导致链接无法访问

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

30常用 Maven 命令

Maven 是一个强大的项目管理和构建工具,它广泛用于 Java 项目的依赖管理、构建流程和插件集成。Maven 的命令行工具提供了大量的命令来帮助开发人员管理项目的生命周期、依赖和插件。以下是 常用 Maven 命令的使用场景及其详细解释。 1. mvn clean 使用场景:清理项目的生成目录,通常用于删除项目中自动生成的文件(如 target/ 目录)。共性规律:清理操作

poj 2135 有流量限制的最小费用最大流

题意: 农场里有n块地,其中约翰的家在1号地,二n号地有个很大的仓库。 农场有M条道路(双向),道路i连接着ai号地和bi号地,长度为ci。 约翰希望按照从家里出发,经过若干块地后到达仓库,然后再返回家中的顺序带朋友参观。 如果要求往返不能经过同一条路两次,求参观路线总长度的最小值。 解析: 如果只考虑去或者回的情况,问题只不过是无向图中两点之间的最短路问题。 但是现在要去要回

poj 3422 有流量限制的最小费用流 反用求最大 + 拆点

题意: 给一个n*n(50 * 50) 的数字迷宫,从左上点开始走,走到右下点。 每次只能往右移一格,或者往下移一格。 每个格子,第一次到达时可以获得格子对应的数字作为奖励,再次到达则没有奖励。 问走k次这个迷宫,最大能获得多少奖励。 解析: 拆点,拿样例来说明: 3 2 1 2 3 0 2 1 1 4 2 3*3的数字迷宫,走两次最大能获得多少奖励。 将每个点拆成两个

poj 2195 bfs+有流量限制的最小费用流

题意: 给一张n * m(100 * 100)的图,图中” . " 代表空地, “ M ” 代表人, “ H ” 代表家。 现在,要你安排每个人从他所在的地方移动到家里,每移动一格的消耗是1,求最小的消耗。 人可以移动到家的那一格但是不进去。 解析: 先用bfs搞出每个M与每个H的距离。 然后就是网络流的建图过程了,先抽象出源点s和汇点t。 令源点与每个人相连,容量为1,费用为

poj 3068 有流量限制的最小费用网络流

题意: m条有向边连接了n个仓库,每条边都有一定费用。 将两种危险品从0运到n-1,除了起点和终点外,危险品不能放在一起,也不能走相同的路径。 求最小的费用是多少。 解析: 抽象出一个源点s一个汇点t,源点与0相连,费用为0,容量为2。 汇点与n - 1相连,费用为0,容量为2。 每条边之间也相连,费用为每条边的费用,容量为1。 建图完毕之后,求一条流量为2的最小费用流就行了

hdu 3065 AC自动机 匹配串编号以及出现次数

题意: 仍旧是天朝语题。 Input 第一行,一个整数N(1<=N<=1000),表示病毒特征码的个数。 接下来N行,每行表示一个病毒特征码,特征码字符串长度在1—50之间,并且只包含“英文大写字符”。任意两个病毒特征码,不会完全相同。 在这之后一行,表示“万恶之源”网站源码,源码字符串长度在2000000之内。字符串中字符都是ASCII码可见字符(不包括回车)。

两个月冲刺软考——访问位与修改位的题型(淘汰哪一页);内聚的类型;关于码制的知识点;地址映射的相关内容

1.访问位与修改位的题型(淘汰哪一页) 访问位:为1时表示在内存期间被访问过,为0时表示未被访问;修改位:为1时表示该页面自从被装入内存后被修改过,为0时表示未修改过。 置换页面时,最先置换访问位和修改位为00的,其次是01(没被访问但被修改过)的,之后是10(被访问了但没被修改过),最后是11。 2.内聚的类型 功能内聚:完成一个单一功能,各个部分协同工作,缺一不可。 顺序内聚:

利用命令模式构建高效的手游后端架构

在现代手游开发中,后端架构的设计对于支持高并发、快速迭代和复杂游戏逻辑至关重要。命令模式作为一种行为设计模式,可以有效地解耦请求的发起者与接收者,提升系统的可维护性和扩展性。本文将深入探讨如何利用命令模式构建一个强大且灵活的手游后端架构。 1. 命令模式的概念与优势 命令模式通过将请求封装为对象,使得请求的发起者和接收者之间的耦合度降低。这种模式的主要优势包括: 解耦请求发起者与处理者