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

现在有没有新的机制来确保一条记录只被处理一次

  •  
  •   muziling · 2020-04-02 10:50:37 +08:00 · 3089 次点击
    这是一个创建于 1700 天前的主题,其中的信息可能已经有所发展或是发生改变。
    单线程,或多线程,怎么保证一条记录只被处理一次
    目前是 处理前把记录状态改为处理中,并判断 update 返回值是否为 1, 是的话,开始处理,否则跳过此记录

    这种方法一条记录就要 update 一次,性能会有损失,而且如果在处理时,程序强制重启了,会造成处理中的记录是否有处理成功并不知道。

    现在 2020 年了,有没有新的解决方案?
    20 条回复    2020-04-02 18:11:30 +08:00
    fancy111
        1
    fancy111  
       2020-04-02 10:53:15 +08:00
    都 2020 年了,你还来问这个问题,连百度收录的都是三五年前的解决方案了。
    muziling
        2
    muziling  
    OP
       2020-04-02 10:56:51 +08:00
    @fancy111 求指教,搜索到的很多时候要花很大精力筛选
    loryyang
        3
    loryyang  
       2020-04-02 11:06:55 +08:00
    重点看你的处理是什么,要多严格的 just once
    muziling
        4
    muziling  
    OP
       2020-04-02 11:13:26 +08:00
    @loryyang 最严格和 允许异常重启时重复一次 ,方案分别是什么, 想了解下,有个底。
    index90
        5
    index90  
       2020-04-02 11:27:23 +08:00
    用 token
    同一时间,只有一个 worker 获得有效 token
    worker 可以利用 token 修改该 task 的状态和访问其相关资源
    dapang1221
        6
    dapang1221  
       2020-04-02 11:30:50 +08:00
    现成的消息队列怎么不用…处理完后回复 ACK 确认
    ThirdFlame
        7
    ThirdFlame  
       2020-04-02 11:33:10 +08:00
    那不就和 人工作业一样么,有 worker 处理了,那设置个标记说明 处理中。 等处理完成了,把标记置为完成。
    jugelizi
        8
    jugelizi  
       2020-04-02 11:35:35 +08:00 via iPhone
    无非是单线程
    或者锁
    muziling
        9
    muziling  
    OP
       2020-04-02 11:44:09 +08:00
    @index90 没能理解,多个 worker,分别执行不同的 task, token 怎么做,或者能给个搜索的关键字吗?
    ZSeptember
        10
    ZSeptember  
       2020-04-02 12:02:23 +08:00
    上面的说法跟 LZ 提的没看出有什么区别

    单线程也很难就直接保证了,没有考虑 处理完成,但是更新状态失败这个问题。

    要 Exactly Once 基本是要业务层保证,幂等,可 redo
    NeinChn
        11
    NeinChn  
       2020-04-02 12:06:29 +08:00
    @dapang1221 现成消息队列大部分不支持 exactly once.大多都是 at least once/at most once
    所以一般还是需要自行做可重入
    index90
        12
    index90  
       2020-04-02 12:25:15 +08:00
    @muziling 我先说一下我对题目的理解,就是有一个分布式作业系统,一个作业只能被一个 worker 执行,worker 可能会突然死掉,多个 worker 会抢占作业。

    首先第一,作业需要有状态机

    第二,为什么一个作业只能由一个 worker 执行,本质原因是这个作业所关联的资源(包括他自身的信息,如状态)只能由一个线程进行读写。那么可以解决资源的访问权限。

    第三,确定状态转移的最大时间,就是 token 的超时时间,你可以依赖 token 超时保证不会再有其他线程在访问你的作业资源。
    also24
        13
    also24  
       2020-04-02 12:33:25 +08:00
    这东西本质上来说就是锁。

    做好超时和释放机制就行。

    举例,任务 task-24,我们用 Redis 来上锁。

    构造 A-value = "ServerA:" + str(now_ts + timeout)
    A 客户端先 SET task-24-key A-value NX
    如果设置成功,说明拿到了锁,那就执行任务。

    直到任务结束,使用一段 Lua 原子性的删除锁。
    伪代码:if GET task-24-key == A-value then DEL task-24-key


    如果刚才的 SET 没成功,说明有别人拿着锁,那就把 value 取出来看下
    K-value = GET task-24-key

    把 K-value 里的 now_ts + timeout 取出来看下过期没。
    如果没过期,说明这个锁还有效,那就休眠等着。

    如果已经过期,那就说明这个锁的主人可能已经死了,开始抢过期锁。
    构造 A-value2 ="ServerA:" + str(now_ts2 + timeout)
    继续扔一段 Lua 上去原子性的抢锁,伪代码:
    if GET task-24-key == A-value
    then
    SET task-24-key A-value2


    然后看一下 task-24-key 的值是否是 A-value2 。
    是的话说明抢到了锁,执行任务,然后删锁……
    不是的话说明锁被别人抢走了,那继续去看过期的问题……没过期就休眠……
    also24
        14
    also24  
       2020-04-02 12:38:10 +08:00
    当然,其实还有更简单的办法:
    SET task-24-key anystring NX EX max-lock-time

    设置成功说明抢到了锁
    设置失败说明没抢到

    任务跑完了就 DEL task-24-key 就行~
    ppcoin
        15
    ppcoin  
       2020-04-02 12:47:26 +08:00
    消息队列 at least once + 幂等的 consumer?
    Chenamy2017
        16
    Chenamy2017  
       2020-04-02 13:19:33 +08:00
    记录中增加一个更新 id,每次更新时如果更新 id 一致则更新,并且更新 id 自增。其他人去更新时发现 id 不一致,则不允许更新。
    reus
        17
    reus  
       2020-04-02 15:23:22 +08:00
    何必保证只处理一次,保证处理多次,作用也相同就行。
    lightingtime
        18
    lightingtime  
       2020-04-02 17:15:06 +08:00
    @also24 那 Redis 那台机器挂了呢
    also24
        19
    also24  
       2020-04-02 17:20:36 +08:00
    @lightingtime #18
    如果需要考虑 Redis 失效,可以考虑直接拿 RedLock 的方案

    简单点说就是,N 台 Redis 机器,只要在 N / 2 + 1 台机器上抢到了锁,就认为锁已经到手,如果只抢到少部分锁,就要及时删除。


    关于 Redlock 的介绍可以参考这里:
    https://redis.io/topics/distlock
    http://redis.cn/topics/distlock.html
    lightingtime
        20
    lightingtime  
       2020-04-02 18:11:30 +08:00
    @also24 thanks
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5925 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 19ms · UTC 01:56 · PVG 09:56 · LAX 17:56 · JFK 20:56
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.