请教一个 Redis 过期时间的问题

2022-09-07 11:23:34 +08:00
 7911364440

程序的逻辑是这样的: 有一个定时任务在执行前会判断 redis 中是否存在数据,如果存在则不执行,如果不存在继续执行,然后在 Redis 中新增数据并且把定时任务间隔时间作为数据的过期时间。

正常情况下,下一次任务执行前 Redis 中一定是没有数据的,但是实际上任务第二次执行的时候 Redis 中的数据总是不为空,后续大部分情况都是正常的,偶尔也会有不为空的。

Redis 扫描过期数据的间隔是 50ms ,也尝试过 timeout = timeout-50 ,也不行!!!

想问下有没有遇到过类似情况的大佬,麻烦指点下!!!

start 是任务开始时的时间戳,timeout 是计算出来的任务间隔时间,也是 redis 的过期时间


start: 1662520720050 timeout: 4950 foo task execute -- 正常执行

start: 1662520725006 timeout: 4994 redis not empty -- 这里第二次总是不为空

start: 1662520730013 timeout: 4987 foo task execute

start: 1662520735004 timeout: 4996 foo task execute

start: 1662520740001 timeout: 4999 foo task execute

start: 1662520745010 timeout: 4989 foo task execute

start: 1662520750005 timeout: 4995 foo task execute

start: 1662520755004 timeout: 4996 foo task execute

start: 1662520760015 timeout: 4985 foo task execute

3369 次点击
所在节点    Java
31 条回复
micean
2022-09-07 14:42:33 +08:00
很多信息没有给,50ms 的要求也很高,时间间隔最好以任务的预估完成时间估算。
比如第一次连接到 redis 的时间消耗的比较长(连接池经常这样),那么第二次扫描 redis 自然有可能还没过期的。

如果是用 redis 做分布式单任务,给你一个简单的方案
1. 用 xxx+时间戳作为键名
2. 时间戳为固定值,比如你的 50ms 的间隔,那么时间戳是 00:00:00.050 、00:00:00.100 、00:00:00.150 等等。如果是 00:00:00.067 运行的任务,那么去除余数是 00:00:00.050 。
3. 用 setnx 就能完成检查+过期
4. 任务计时器的线程不要承担业务代码
fkdtz
2022-09-07 14:43:02 +08:00
Redis 过期策略确实是惰性删除的,但那也不意味着本该删掉的 key 还能 get 出来,如果是这样那过期有个毛用了。
感觉是你的业务逻辑写的有问题,get key 、set key 、set job start time 这三步哪里有问题,导致出现了时间差。
不行贴代码吧。
tutu2000
2022-09-07 15:03:48 +08:00
”判断 redis 中是否存在数据“跟过期 key 是否被删除没关系,只要过期了的 key ,redis 肯定返回不存在
看你设置的过期时间很短,很可能第二次任务写入时慢了,之后的任务又快了,导致差了几毫秒 key 还没过期。建议设置绝对过期时间试下,expireat
baoyinlei
2022-09-07 15:26:18 +08:00
定时任务开启到 redis server 端真正执行命令也是需要时间的。
xuanbg
2022-09-07 15:50:42 +08:00
才 50ms 就扫一次的任务最好放内存别放 redis 。读取 redis 数据怎么也要几个毫秒,影响太大了。
buster
2022-09-07 15:54:55 +08:00
开始执行定时任务:00:00:00
checkExists request:00:00:01
NO and set Interval = 1min:00:00:02
-------------------------------------------
下一个循环开始:00:01:00
checkExists request:00:01:01
此时那个 key 的 ttl 还剩余 1 到 2 秒,exist !
dddd1919
2022-09-07 15:58:37 +08:00
50ms 的精度要求太高,网络稍微抖动就 gg
corningsun
2022-09-07 16:12:38 +08:00
换个思路就好了,用多个 key 替换原来的一个 key

假设定时任务时间间隔是 1 秒,每次定时任务开始,就去设置这个 key ,只有 返回 true 才继续执行任务

setIfPresent(task_yyyyMMddHHmmss, Duration.of(超过定时任务间隔的时间) )
Chinsung
2022-09-07 17:02:37 +08:00
你这个到 ms 级,本来就不准
你定时任务触发的时间戳,我们假设你是 xxl-job 或者 quartz 这种,xxl-job 触发的时间戳是 0,50ms,100ms
但是你定时任务触发时到你服务器的网络延迟,或者哪怕你是单机定时任务的线程切换延迟,再到你执行到 redis set 的延迟,再到 redis 请求的网络延迟,都可能会导致问题。
比如你任务触发是时钟 0ms ,设置 redis 实际是 1ms 了,那你 redis 过期时间到 51ms ,显然就有问题了
urnoob
2022-09-07 17:20:54 +08:00
50ms 确实太短,局域网内可能都没那么快。
实现上给不要用 key 是否存在来做,放一对 kv ,判断的时候用 key 去取 v ,应该能避免你这种情况
Orlion
2022-09-08 10:10:04 +08:00
提个醒 exists 命令在 4.0.11 以下版本的 redis 主从架构中是有 bug 的,详情请看: https://www.cnblogs.com/mysql-dba/p/15870868.html

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/878310

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX