单纯做技术讨论,使用 PG 数据库实现一个分布式锁。仅考虑锁的正确性,不考虑可重入等功能。我的想法如下。
create table distribute_locks ( id varchar not null primary key, expire_at timestamptz not null, created_at timestamptz not null default current_timestamp, updated_at timestamptz not null default current_timestamp );
insert into distribute_locks (id, expire_at) values (:id, now() + interval '1 minute') on conflict (id) do update set expire_at = now() + interval '1 minute' where distribute_locks.expire_at < current_timestamp returning id
有内容返回时获取锁成功,否则获取锁失败
update distribute_locks set expire_at = now() + interval '1 minute' where id = :id and expire_at > current_timestamp
只有锁存在且过期才能续期,否则续期无效
delete from distribute_locks where id = :id
这样设计的锁能满足基本需求了,但还有一个问题没有解决,即如何稳定续期。
问题点在于,如果我在获取到锁时启动一个线程去续期,那如果当前线程结束,没有主动释放锁。该续期线程要如何结束呢?
我用的是 python 来做
![]() | 1 opengps 2023-06-27 16:35:25 +08:00 我没看明白,这个 distribute_locks 表存在哪,因为我始终都想知道怎么实现的分布式锁。 因为我关注点是:这到底是多个数据库的锁,还是分布式应用的共享一个库里的行数据作为锁 |
2 zuisong 2023-06-27 17:38:38 +08:00 设置一个最大续期次数? |
![]() | 3 F281M6Dh8DXpD1g2 2023-06-27 17:39:35 +08:00 先想想隔离级别的事 |
7 leonshaw 2023-06-27 18:04:55 +08:00 续期的时候不看所有权? |
9 lolizeppelin 2023-06-27 18:14:24 +08:00 直接 zk 或者 etcd 做不就行了....为什么折腾 pg 数据库做锁没法支持连接断开后清理锁,用 expire_at 很别扭的 字段里加个 lokcer 存放 uuid, 这个 uuid 由于获得上锁的客户端生成, 由于这个 uuid 只有上锁的客户端才知道,这样就可以做到过期前只有指定的 locker 才能释放 上锁 update lock set locker = 'fffffffffffffffffffffffffffffffffffff' where id = 'locker-id' and locker is null 放锁 update lock set locker = null where id = 'locker-id' and locker = 'fffffffffffffffffffffffffffffffff' |
10 shinyruo2020 2023-06-27 18:41:23 +08:00 没看懂,为什么发现冲突时是去续期呢?不用判断当前线程是否持有锁的吗? |
11 shinyruo2020 2023-06-27 18:42:32 +08:00 噢噢,看到你上面的回复了,sry |
![]() | 12 voidmnwzp 2023-06-27 18:46:13 +08:00 via iPhone 分布式锁不都是 zk 或者 redis 不会用硬盘数据库吧 |
![]() | 13 rrfeng 2023-06-27 19:00:14 +08:00 只要逻辑没错,你用啥都行。 只要是可靠的强一致性的支持事务的存储,都可以用来做分布式锁。很多时候没必要引入 redis/zk 。 |
![]() | 14 xiangyuecn 2023-06-27 19:22:16 +08:00 删除也一样要校验所有权。简单加一个随机值,谁持有这个随机值就代表谁持有这个锁,可删除和更新(不管过期不过期都能操作,逻辑上简单粗暴)。 |
![]() | 15 wqtacc 2023-06-27 23:29:44 +08:00 感觉现在的实现,如果是多个客户端,加锁时的 id 怎么分配的,冲突就展期,防止不了冲突,释放锁也是一样的 |