Postgres死锁检测器并不总是工作?

时间:2015-08-06 11:33:00

标签: postgresql locking postgresql-9.4

我们最近在Posgres 9.4遇到了一些死锁问题。 有些查询根本没有返回,只会无限期挂起。 经过一番调查,我们发现进程死锁似乎是个问题。从Lock Monitoring Postgres Wiki运行查询时,我们会看到一大堆被阻止的进程。解决这些问题的唯一方法就是开始杀死其中一些进程,直到Postgres再次解决问题为止。

现在我的理解是,Postgres中的死锁检测器应该能够找出存在死锁然后通过回滚其中一个被阻塞的事务来解决它,以便另一个可以继续然后重试第一。 但这不是我们的情况,这些过程在我们杀死它们之前无限期地陷入僵局。

deadlock_timeout设置为1s(默认值),我找不到打开或关闭死锁检测器的标志,所以我认为它始终打开。

所以我的问题是死锁检测器是否只能检测某些类型的死锁,如果是,那么哪些死锁?

为什么Lock Monitoring Wiki上显示的查询可以检测死锁进程,但死锁检测器本身不能?

2 个答案:

答案 0 :(得分:2)

  

现在我的理解是,Postgres中的死锁检测器应该能够找出存在死锁然后通过回滚其中一个被阻塞的事务来解决它,以便另一个可以继续然后重试第一个。

只有在PostgreSQL后端之间出现死锁的情况下才会出现这种情况,其中每个后端都在等待另一个后端。

人们似乎经常希望死锁检测器能够处理死锁通过应用层的情况。事实并非如此。

死锁检测器可以处理:

  • tx1对表x的第1行保持锁定,尝试更新表x的第2行
  • tx2对表x的第2行保持锁定,尝试更新表x的第1行

它可以帮助:

  • 应用程序线程拥有与tx1的会话正在等待另一个线程B
  • 的结果
  • tx1在打开的事务中保持对表x的第1行的锁定
  • 应用程序线程B拥有与tx2
  • 的会话
  • tx2正在尝试更新表x的第1行,其中tx1已经存在

这两个都是死锁。 PostgreSQL只能帮助第一个。它无法知道应用程序状态是什么,并且不知道tx1永远无法进行并且在tx2等待的行上释放其锁定,因为拥有它的应用程序线程正在等待tx2完成。死锁涉及数据库中的等待和应用程序中的等待,并且都没有完整的图片。

请注意,等待另一个查询的一个查询是死锁。只有在一个无法打破的循环的情况下才会出现死锁,因为没有后端可以在没有其他进展的情况下继续进行,并且它们都在等待彼此。

很可能你的情况就像第二种情况,应用程序涉及死锁。

答案 1 :(得分:2)

如果可以看到两个交易相互等待,Postgres只会发现死锁。特别是对于两个(或更多)过程,场景必须是:

  • A需要获取由B锁定的资源。
  • B需要获取由A锁定的资源。

死锁处理不会处理以下情况:

  • 需要获取由B锁定的资源。
  • B将表锁定在交互式psql会话中然后接受了 下午休息,没有提交,回滚或退出。

根据您的描述,听起来您的某个数据库会话未释放其资源。也许它缺少一个COMMIT等。就Postgres而言,它并不是一个僵局,因为众所周知,为什么这个锁持有这么长时间是完全正确的理由。

您可以做的一件事是设置锁定超时。这意味着进程在放弃并标记问题之前等待尝试获取锁定的时间有一个上限。

锁定超时和其他设置记录在: http://www.postgresql.org/docs/9.3/static/runtime-config-client.html