[分布式设计] 没有 Redis 分布式锁如何保证操作的一致性?

83 天前
 Charlie17Li

背景

应用实例部署在多个机房,不同机房的应用实例使用同一个 DB ,但是受 xxx 风险规则,不同机房不能够使用同一个 Redis:

然而应用中有一个定时任务会按时扫描 DB 中的某个表的记录执行相应的动作 Action ,并将结果回写到这条记录中。

一个非常直觉的想法是,使用分布式锁实现某个记录只有一个应用实例在操作。但受限于上述规则而无法实现。

因此,想问下该怎么实现才能保证一个记录不会被多个实例同时操作呢?

思考

目前几个非常直觉的想法是:

1.应用在扫表后会得到一批记录,每次在执行动作 Action 之前,给这个记录加个行锁?理论上是可行的,但不知道这种加锁的方式是否合适以及代价/风险。

2.每次只让一个机房的应用实例扫表,这样子同机房就可以使用 Redis

3.给 DB 加个字段让每个机房只搞自己的,当某个机房发生故障的时候手动改配置,让另外一个健康机房可以扫故障机房的单子。

感觉方法都有点野蛮... 另外这需求其实用消息队列应该是比较优质的解法,但目前规模不大,都不太想用到 Q...

2557 次点击
所在节点    程序员
27 条回复
mooyo
83 天前
我感觉怎么设计都会有问题,一个最核心的问题是 你的 action 是可以重放的吗。如果不是的话,即使有 redis 分布式锁,你怎么解决如果扫到一个 action ,执行了一半挂了的情况呢。
zdking08135
83 天前
尽量设计成一个实例操作一部分数据,没必要用锁竞争。
做好监控的话,实例挂了的情况其实很少见,直接处理就行了。
Maboroshii
83 天前
使用 db 实现分布式锁是一样的啊,乐观锁 update
GeekGao
83 天前
同意楼上观点
GeekGao
83 天前
Aruforce
83 天前
@Maboroshii 这个挺好的
Goooooos
83 天前
db 建一个 lock 表,里面只有一个主键和一个 version ,就能实现乐观锁
yangtianming
83 天前
楼主想要实现的就是分布式锁,感觉学的有点死了,分布式锁可以通过 redis 实现,当然也可以通过 mysql 实现
yangtianming
83 天前
@yangtianming #8
不好意思,惯性思维 mysql 了 ,其他 db 也是一样
dddd1919
83 天前
既然是数据库,那直接行锁啊😂,如果没有大量并发,用 redis 加锁也属实倒反天罡
sagaxu
83 天前
1. 行锁可能会跟其它业务逻辑中的行锁打架,锁时间长了影响业务,加多了还容易死锁,
2. 如果扫表负载不高,直接指定某个机房负责扫表也行,不用分配也不用轮流
3. 不用加字段,直接按 ID 分配机房就行,出问题了手动切

2 或 3 都行,把切机房的开关做方便点
ys1992
83 天前
"不同机房的应用实例使用同一个 DB" 这不就是天然实现分布式锁的基础设施么,没必要纠结非要使用 redis ,把 redis 分布式锁 setnx 和 expire ,用数据库的方式实现一遍就可以了呀,
举个例子,来个 lock 表,lock_name 作为唯一索引,加一个 lock_status 状态,expire_time 过期时间,
获取锁的时候 update lock set lock_status = 1 where lock_name = xxx and (lock_status = 0 or expire_time<now())
释放锁的时候 update lock set lock_status = 0 where lock_name = xxx and lock_status = 1
vishun
83 天前
直接最简单的,数据库悲观锁 for update ,隔离级别设置为 RC ,貌似 RR 会有间隙锁导致的死锁。
roidinev
83 天前
扫表看起来也是弱一致性动作。也要考虑协调问题
billbur
83 天前
我们的做法是第一个做好幂等,也就是任务可以被重复执行但不会出现错误,另一个是根据某个字段做分片,取余或者一致型哈希算法去做,一个机房只处理一部分数据
jorneyr
83 天前
select for update 语句可以实现分布式锁。
yh7gdiaYW
83 天前
@ys1992 MySQL 在高并发下更新同一条数据可能会出现死锁,不如 Redis 用的省事儿。不过我也只是看过些案例没自己用 mysql 这么加过锁,也不清楚别的数据库是否也有这类问题
pangdundun996
83 天前
1 ) DB 实现分布式锁
2 )如果可访问多机房的话,引入调度节点
dododada
83 天前
7 楼的方案没啥问题,你也没有数据同步什么的,顶天就是个缓存数据不一致
Charlie17Li
83 天前
@mooyo 实际上是可以重放的,被扫的这个表实际包含新建的任务和之前执行失败的任务的记录。

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

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

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

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

© 2021 V2EX