请教一个 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

3078 次点击
所在节点    Java
31 条回复
kailyn
2022-09-07 11:42:17 +08:00
过期时间是不严格的,并不是你设置多久,多后就真的过期。好像是有个专门负责处理过期 key 的线程,类似于按照一定时间轮询遍历 key ,判断过期了再删除。
zmal
2022-09-07 11:42:50 +08:00
定时任务的时间间隔没那么准,和 redis 没啥关系。你这个方案问题也蛮多的,redis 执行延迟、定时任务阻塞都会导致不可靠。
zmal
2022-09-07 11:48:45 +08:00
1L 说的不准确,redis 的定期删除和惰性删除能保证在第二次 get 时确定是否删除。但 redis 过期是在 redis 服务写入成功后开始算的,不包含你的服务远程发送到 redis + redis 接收执行 的时延。
7911364440
2022-09-07 11:49:41 +08:00
@zmal 两次相邻的任务间隔算了下都是大于超时时间的,感觉跟定时任务应该没关系
vzhzhq
2022-09-07 11:51:40 +08:00
数据过期不等于没有数据,redis 的淘汰策略可以了解一下
Red998
2022-09-07 11:54:21 +08:00
过期时间这个有点不可靠 。 办法一:监听 redis key 过期的事件 可以达到你的目的。但是会消耗一定的 cpu
办法二:监听 binlog 来实现 。只要有更新你就刷进 redis 。完全不管有没有超时。
办法三:类似心跳方案、一个定时任务 每隔几秒就去刷数据 setNx 也可以
zmal
2022-09-07 11:59:44 +08:00
这个设计没法用,换方案吧。
DavidDee
2022-09-07 12:00:58 +08:00
DavidDee
2022-09-07 12:01:35 +08:00
@DavidDee 自动就发了。。OP 看下是不是文章最后的说的惰性删除导致的问题?
liuzhaowei55
2022-09-07 12:05:01 +08:00
总感觉怪怪的,不能这样依赖两个事件去触发更新,流程有点乱。redis 直接设置一个较长的过期时间,然后定时任务自己设定更新频率,刷掉旧数据,然后是任务调度这些毫秒的误差不太好保证,差一两秒都是可能的。
可以重新讲讲使用场景
RedBeanIce
2022-09-07 12:53:54 +08:00
建议不要问 ab 问题,因为 a 产生 b ,问 b
RedBeanIce
2022-09-07 12:54:40 +08:00
抱歉,我错了,请忽略我
IvanLi127
2022-09-07 13:07:41 +08:00
有数据的时候你把 ttl 查出来打印下看看呀?还要你要解决啥问题?我感觉 redis 过期时间不精确也很合理呀
seth19960929
2022-09-07 13:20:47 +08:00
Redis 设置了过期时间, 肯定就是那个时间点过期. 楼上说的有问题
过期了 != 删除.
redis 判断一个 key 不存在有两种, 一种是 key 不存在, 另一种是存在, 但是过期了没来得及删除
楼主这个不就是最简单的单任务锁吗, 如果服务器延迟大的话
尝试使用 EXPIREAT 设置过期时间, 而不是 EXPIRE
JKeita
2022-09-07 13:39:54 +08:00
先了解下 redis 得过期删除策略
nothingistrue
2022-09-07 13:43:25 +08:00
利用 Redis 搞延时任务,要用 zset ,不能用 timeout 。具体的我就不说了,因为我也是看别人的,以关键词“分布式之延时任务方案解析”来自行搜索吧。
7911364440
2022-09-07 13:46:51 +08:00
@IvanLi127 看了下第二次任务执行的时候,数据的过期时间大概还剩 850ms 左右。之后的数据基本上是可以正常过期的,只有第二次不行,就很奇怪
edward1987
2022-09-07 14:05:35 +08:00
换个实现方式+1
总感觉你在走弯路...不如说下需求
mitu9527
2022-09-07 14:15:58 +08:00
要么是个高级问题,要么是个低级问题,目前看不出来是哪种。
Jooooooooo
2022-09-07 14:32:37 +08:00
是想用 redis 去做到毫秒级别的过期控制?

你得换个实现方案. 或者你的需求本身有问题.

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

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

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

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

© 2021 V2EX