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

4 天前
 Charlie17Li

背景

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

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

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

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

思考

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

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

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

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

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

2042 次点击
所在节点    程序员
27 条回复
Charlie17Li
4 天前
@zdking08135 每个实例操作一部分数据这个有什么最佳实践吗?
wangliran1121
4 天前
select for update
8355
4 天前
啊?这不是最传统的简单方案就可以解决的吗
mysql 抢占啊
增加一个状态字段 假设 active_status = 0 未启动
按照不同机房你最多有 2 个实例参与抢占
update table set active_status = 1 where id = xxx
看影响行数 = 1 视为抢占成功,开始执行就行了。。 其他的 return
为啥还需要分布式锁之类的,mysql update 一定是原子的啊
bingNew
3 天前
-- 创建锁表
CREATE TABLE distributed_lock (
lock_name VARCHAR(255) PRIMARY KEY,
locked_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 尝试获取锁
INSERT INTO distributed_lock (lock_name) VALUES ('my_lock')
ON DUPLICATE KEY UPDATE locked_at = CURRENT_TIMESTAMP;

-- 检查是否获取成功
SELECT COUNT(*) FROM distributed_lock WHERE lock_name = 'my_lock';-- 创建锁表
CREATE TABLE distributed_lock (
lock_name VARCHAR(255) PRIMARY KEY,
locked_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 尝试获取锁
INSERT INTO distributed_lock (lock_name) VALUES ('my_lock')
ON DUPLICATE KEY UPDATE locked_at = CURRENT_TIMESTAMP;

-- 检查是否获取成功
SELECT COUNT(*) FROM distributed_lock WHERE lock_name = 'my_lock';
happyxhw101
3 天前
@Goooooos 不应该是悲观锁吗?
desolekk
3 天前
学习一下
hapeman
2 天前
乐观锁版本号

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

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

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

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

© 2021 V2EX