gpt4 book ai didi

sql - SELECT FOR UPDATE 的奇怪死锁 PostgreSQL 死锁问题

转载 作者:太空狗 更新时间:2023-10-30 01:53:44 25 4
gpt4 key购买 nike

我正在构建一个基于 PostgreSQL 的锁定系统,我有两种方法,acquirerelease

对于acquire,它是这样工作的

BEGIN
while True:
SELECT id FROM my_locks WHERE locked = false AND id = '<NAME>' FOR UPDATE
if no rows return:
continue
UPDATE my_locks SET locked = true WHERE id = '<NAME>'
COMMIT
break

并用于发布

BEGIN
UPDATE my_locks SET locked = false WHERE id = '<NAME>'
COMMIT

这看起来很简单,但行不通。奇怪的是,我想

SELECT id FROM my_locks WHERE locked = false AND id = '<NAME>' FOR UPDATE

仅当目标行的 lockedfalse 时,才应获取目标行上的锁。但实际上,并非如此。不知何故,即使不存在 locked = false 行,它仍然会获取锁。结果,我遇到了死锁问题。看起来像这样

Select for update dead lock issue

Release 正在等待 SELECT FOR UPDATE,并且 SELECT FOR UPDATE 在无缘无故地持有锁的同时进行无限循环。

为了重现这个问题,我在这里写了一个简单的测试

https://gist.github.com/victorlin/d9119dd9dfdd5ac3836b

你可以用psycopg2pytest来运行它,记得更改数据库设置,然后运行

pip install pytest psycopg2
py.test -sv test_lock.py

最佳答案

测试用例是这样的:

  • 线程 1 运行 SELECT 并获取记录锁。
  • 线程 2 运行 SELECT 并进入锁的等待队列。
  • 线程 1 运行 UPDATE/COMMIT 并释放锁。
  • 线程 2 获取锁。检测到记录自 SELECT 以来发生了更改,它根据 WHERE 条件重新检查数据。检查失败,该行从结果集中被过滤掉,但锁仍然持有。

FOR UPDATE documentation 中提到了此行为:

...rows that satisfied the query conditions as of the query snapshot will be locked, although they will not be returned if they were updated after the snapshot and no longer satisfy the query conditions.

这可以有一些unpleasant consequences ,因此考虑到所有因素,多余的锁并没有那么糟糕。

可能最简单的解决方法是通过在每次 acquire 迭代后提交来限制锁定持续时间。有多种其他方法可以防止它持有此锁(例如 SELECT ... NOWAIT,以 REPEATABLE READSERIALIZABLE 隔离级别运行, SELECT ... SKIP LOCKED 在 Postgres 9.5 中)。

我认为使用这种重试循环方法的最简洁的实现是完全跳过 SELECT,只运行 UPDATE ... WHERE locked = false,提交每一次。您可以通过在调用 cur.execute() 之后检查 cur.rowcount 来判断您是否获得了锁。如果需要从锁定记录中提取其他信息,可以使用 UPDATE ... RETURNING 语句。

但我必须同意 @Kevin ,并说您最好利用 Postgres 的内置锁定支持而不是尝试重新发明它。它会为你解决很多问题,例如:

  • 自动检测死锁
  • 等待进程进入休眠状态,而不必轮询服务器
  • 锁定请求排队,防止饥饿
  • 锁(通常)不会超过失败的进程

最简单的方法可能是将 acquire 实现为 SELECT FROM my_locks FOR UPDATE,将 release 简单地实现为 COMMIT ,并让进程竞争行锁。如果您需要更大的灵 active (例如阻塞/非阻塞调用、事务/ session /自定义范围),advisory locks应该证明是有用的。

关于sql - SELECT FOR UPDATE 的奇怪死锁 PostgreSQL 死锁问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31850567/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com