现在有没有新的机制来确保一条记录只被处理一次
目前是 处理前把记录状态改为处理中,并判断 update 返回值是否为 1, 是的话,开始处理,否则跳过此记录
这种方法一条记录就要 update 一次,性能会有损失,而且如果在处理时,程序强制重启了,会造成处理中的记录是否有处理成功并不知道。
现在 2020 年了,有没有新的解决方案?
这种方法一条记录就要 update 一次,性能会有损失,而且如果在处理时,程序强制重启了,会造成处理中的记录是否有处理成功并不知道。
现在 2020 年了,有没有新的解决方案?
单线程也很难就直接保证了,没有考虑 处理完成,但是更新状态失败这个问题。
要 Exactly Once 基本是要业务层保证,幂等,可 redo
首先第一,作业需要有状态机
第二,为什么一个作业只能由一个 worker 执行,本质原因是这个作业所关联的资源(包括他自身的信息,如状态)只能由一个线程进行读写。那么可以解决资源的访问权限。
第三,确定状态转移的最大时间,就是 token 的超时时间,你可以依赖 token 超时保证不会再有其他线程在访问你的作业资源。
做好超时和释放机制就行。
举例,任务 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 。
是的话说明抢到了锁,执行任务,然后删锁……
不是的话说明锁被别人抢走了,那继续去看过期的问题……没过期就休眠……
设置成功说明抢到了锁
设置失败说明没抢到
任务跑完了就 DEL task-24-key 就行~
简单点说就是,N 台 Redis 机器,只要在 N / 2 + 1 台机器上抢到了锁,就认为锁已经到手,如果只抢到少部分锁,就要及时删除。
关于 Redlock 的介绍可以参考这里:
https://redis.io/topics/distlock
http://redis.cn/topics/distlock.html