V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
90928yao
V2EX  ›  程序员

redis 的 incr 的过期时间问题

  •  
  •   90928yao · 2019-12-13 13:57:39 +08:00 · 11591 次点击
    这是一个创建于 1799 天前的主题,其中的信息可能已经有所发展或是发生改变。

    incr 过期时间的设置有点纠结 现在俩种方案

    第一个

    value = get(key)
    if (value == null) {
    	incr(key)
        expire(key)
    } else{
    		incr(key)
    }
    

    还有就是 用一次设置一次

    incr(key)
    expire(key)
    

    那个好一点

    15 条回复    2022-07-28 19:34:05 +08:00
    lhx2008
        1
    lhx2008  
       2019-12-13 14:02:55 +08:00 via Android   ❤️ 1
    inc 有返回值的
    optional
        2
    optional  
       2019-12-13 14:07:19 +08:00 via iPhone
    lua
    90928yao
        3
    90928yao  
    OP
       2019-12-13 14:08:51 +08:00
    @lhx2008 靠返回值判断 多线程会有问题的吧
    lhx2008
        4
    lhx2008  
       2019-12-13 14:09:15 +08:00 via Android
    @90928yao 你现在这个才有多线程问题
    codergrowing
        5
    codergrowing  
       2019-12-13 14:12:42 +08:00
    我一般都是用的第二种方案,省去了判断,少了一步操作。代价只是 key 被多缓存一段时间多占用一点内存而已。
    90928yao
        6
    90928yao  
    OP
       2019-12-13 14:16:25 +08:00
    @lhx2008 想通了 谢谢
    swulling
        7
    swulling  
       2019-12-13 14:16:29 +08:00
    先不考虑多线程问题,你这两个方案不等价。
    BBCCBB
        8
    BBCCBB  
       2019-12-13 14:17:24 +08:00
    if value == null :
    set(key, 1, ttl=xxx)
    else:
    incr(key)


    这样行不行, set 命令支持直接设置 ttl
    BBCCBB
        9
    BBCCBB  
       2019-12-13 14:18:48 +08:00
    incr 和 expire 分两步执行是有问题的, 网络抖动等会导致可能设置不到 ttl, 就完蛋了
    swulling
        10
    swulling  
       2019-12-13 14:30:02 +08:00
    如果希望用方案 2,加一个 multi exec 事务就行了。我个人更喜欢事务,非不得已不用 lua
    rrfeng
        11
    rrfeng  
       2019-12-13 14:59:24 +08:00 via Android
    incr 不存在的自动置 0 并递增
    multi incr expire exec
    qxg
        12
    qxg  
       2019-12-13 15:28:45 +08:00
    刚好有这个需求,目前的方案是采用 multi incr + expire,但是耗时比单独 incr 高很多,所以后续优化考虑在本地做一个 map 的缓存,第一次 incr 的时候使用 multi incr + expire,并将 key 存到本地的 map 里,后续只需要判断下本地的 map 里是否存在该 key,如果存在,只需执行 incr 即可。
    tr0uble
        13
    tr0uble  
       2019-12-13 16:24:15 +08:00
    ok = set key 1 nx ex 10
    if ok :
    count =1
    else:
    count = incr key
    hipop
        14
    hipop  
       2021-03-16 10:20:08 +08:00
    lua 脚本

    count = incr key
    if (count == 1) then
    expire key 10000
    end
    chengzi
        15
    chengzi  
       2022-07-28 19:34:05 +08:00
    ```
    value = get(key)
    if (value == null) {
    incr(key)
    expire(key) // incr(), expire() 需要保证原子性, 需要用 multi(), exec() 包一下
    } else{
    incr(key) // get(), incr() 中间是有时间差的, 如果 incr() 时 key 已经过期, 就会出现 key 无法过期释放问题
    }
    ```
    最简单的方案是用 lua 脚本, 或者参考 redis 官网文档里的 RPUSHX 方案 ( https://redis.io/commands/incr/)
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5012 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 09:37 · PVG 17:37 · LAX 01:37 · JFK 04:37
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.