请教一个 Redis 过期时间的问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
7911364440
V2EX    Java

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

  •  
  •   7911364440 2022-09-07 11:23:34 +08:00 3860 次点击
    这是一个创建于 1162 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

    Reis 扫描过期数据的间隔是 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

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

    你得换个实现方案. 或者你的需求本身有问题.
    micean
        21
    micean  
       2022-09-07 14:42:33 +08:00   1
    很多信息没有给,50ms 的要求也很高,时间间隔最好以任务的预估完成时间估算。
    比如第一次连接到 redis 的时间消耗的比较长(连接池经常这样),那么第二次扫描 redis 自然有可能还没过期的。

    如果是用 reds 做分布式单任务,给你一个简单的方案
    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
        22
    fkdtz  
       2022-09-07 14:43:02 +08:00
    Redis 过期策略确实是惰性删除的,但那也不意味着本该删掉的 key 还能 get 出来,如果是这样那过期有个毛用了。
    感觉是你的业务逻辑写的有问题,get key 、set key 、set job start time 这三步哪里有问题,导致出现了时间差。
    不行贴代码吧。
    tutu2000
        23
    tutu2000  
       2022-09-07 15:03:48 +08:00
    ”判断 redis 中是否存在数据“跟过期 key 是否被删除没关系,只要过期了的 key ,redis 肯定返回不存在
    看你设置的过期时间很短,很可能第二次任务写入时慢了,之后的任务又快了,导致差了几毫秒 key 还没过期。建议设置绝对过期时间试下,expireat
    baoyinlei
        24
    baoyinlei  
       2022-09-07 15:26:18 +08:00
    定时任务开启到 redis server 端真正执行命令也是需要时间的。
    xuanbg
        25
    xuanbg  
       2022-09-07 15:50:42 +08:00
    才 50ms 就扫一次的任务最好放内存别放 redis 。读取 redis 数据怎么也要几个毫秒,影响太大了。
    buster
        26
    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
        27
    dddd1919  
       2022-09-07 15:58:37 +08:00
    50ms 的精度要求太高,网络稍微抖动就 gg
    corningsun
        28
    corningsun  
       2022-09-07 16:12:38 +08:00
    换个思路就好了,用多个 key 替换原来的一个 key

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

    setIfPresent(task_yyyyMMddHHmmss, Duration.of(超过定时任务间隔的时间) )
    Chinsung
        29
    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
        30
    urnoob  
       2022-09-07 17:20:54 +08:00
    50ms 确实太短,局域网内可能都没那么快。
    实现上给不要用 key 是否存在来做,放一对 kv ,判断的时候用 key 去取 v ,应该能避免你这种情况
    Orlion
        31
    Orlion  
       2022-09-08 10:10:04 +08:00
    提个醒 exists 命令在 4.0.11 以下版本的 redis 主从架构中是有 bug 的,详情请看: https://www.cnblogs.com/mysql-dba/p/15870868.html
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5313 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 51ms UTC 07:11 PVG 15:11 LAX 23:11 JFK 02:11
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86