依靠 Postgres 的死锁检测来进行并发控制是否安全?
Is it safe to rely on Postgres' deadlock detection for concurrency control?
我的应用程序 运行 偶尔会陷入死锁,因为两个事务需要更新相同的行但顺序不同(例如,事务 A 更新行 X 然后 Y,而事务 B 更新行 Y 然后 X).
由于各种原因,解决避免这种死锁的传统方法——锁定或以一致的顺序更新行——不太理想。
由于我尝试执行的更新在其他方面是幂等的并且与顺序无关,所以简单地在应用程序级别捕获这些偶尔出现的死锁并重试事务是否安全合理?
例如:
def process_update(update):
attempt = 0
while attempt < 10:
try:
execute("SAVEPOINT foo")
for row in update:
execute("UPDATE mytable SET … WHERE …", row)
execute("RELEASE SAVEPOINT foo")
break
except Deadlock:
execute("ROLLBACK TO SAVEPOINT foo")
attempt += 1
raise Exception("Too many retries")
这个想法合理吗?或者是否存在与 Postgres 的死锁检测相关的成本,这可能会使其变得危险?
我针对同一张表上有 50 到 100 个并发进程的系统进行了大量研究和实验。除了基本的死锁之外,还可能发生许多事务失败。我的案例包括读取已提交和可序列化的事务。在应用程序级别处理此问题不会导致任何问题。幸运的是 Postgres 会立即失败,所以唯一的性能影响是应用程序,对数据库没有什么影响。
关键组件每type of error, knowing which cases require a rollback, and having an exponential backoff for retries抓一次。我发现立即重试或静态睡眠时间会导致进程简单地反复死锁并导致有点多米诺骨牌效应,这是有道理的。
这是我的系统处理每个并发问题所需的完整逻辑(伪代码):
begin transaction (either read committed or serializable)
while not successful and count < 5
try
execute sql
commit
except
if error code is '40P01' or '55P03'
# Deadlock or lock not available
sleep a random time (200 ms to 1 sec) * number of retries
else if error code is '40001' or '25P02'
# "In failed sql transaction" or serialized transaction failure
rollback
sleep a random time (200 ms to 1 sec) * number of retries
begin transaction
else if error message is 'There is no active transaction'
sleep a random time (200 ms to 1 sec) * number of retries
begin transaction
increment count
我的应用程序 运行 偶尔会陷入死锁,因为两个事务需要更新相同的行但顺序不同(例如,事务 A 更新行 X 然后 Y,而事务 B 更新行 Y 然后 X).
由于各种原因,解决避免这种死锁的传统方法——锁定或以一致的顺序更新行——不太理想。
由于我尝试执行的更新在其他方面是幂等的并且与顺序无关,所以简单地在应用程序级别捕获这些偶尔出现的死锁并重试事务是否安全合理?
例如:
def process_update(update):
attempt = 0
while attempt < 10:
try:
execute("SAVEPOINT foo")
for row in update:
execute("UPDATE mytable SET … WHERE …", row)
execute("RELEASE SAVEPOINT foo")
break
except Deadlock:
execute("ROLLBACK TO SAVEPOINT foo")
attempt += 1
raise Exception("Too many retries")
这个想法合理吗?或者是否存在与 Postgres 的死锁检测相关的成本,这可能会使其变得危险?
我针对同一张表上有 50 到 100 个并发进程的系统进行了大量研究和实验。除了基本的死锁之外,还可能发生许多事务失败。我的案例包括读取已提交和可序列化的事务。在应用程序级别处理此问题不会导致任何问题。幸运的是 Postgres 会立即失败,所以唯一的性能影响是应用程序,对数据库没有什么影响。
关键组件每type of error, knowing which cases require a rollback, and having an exponential backoff for retries抓一次。我发现立即重试或静态睡眠时间会导致进程简单地反复死锁并导致有点多米诺骨牌效应,这是有道理的。
这是我的系统处理每个并发问题所需的完整逻辑(伪代码):
begin transaction (either read committed or serializable)
while not successful and count < 5
try
execute sql
commit
except
if error code is '40P01' or '55P03'
# Deadlock or lock not available
sleep a random time (200 ms to 1 sec) * number of retries
else if error code is '40001' or '25P02'
# "In failed sql transaction" or serialized transaction failure
rollback
sleep a random time (200 ms to 1 sec) * number of retries
begin transaction
else if error message is 'There is no active transaction'
sleep a random time (200 ms to 1 sec) * number of retries
begin transaction
increment count