如何在Postgres中调试ShareLock



我在Postgres服务器日志中看到了很多以下情况:

LOG:  process x still waiting for ShareLock on transaction y after 1000.109 ms 
DETAIL:  Process holding the lock: z. Wait queue: x.
CONTEXT:  while inserting index tuple (a,b) in relation "my_test_table"
SQL function "my_test_function" statement 1 
...
LOG:  process x acquired ShareLock on transaction y after 1013.664 ms
CONTEXT:  while inserting index tuple (a,b) in relation "my_test_table"

我正在运行 Postgres9.5.3。此外,我在 Heroku 上运行,因此我无法访问细粒度的仅限超级用户的调试工具。

鉴于这些约束以及每个单独的锁相对瞬态(通常为 1000-2000ms),我想知道如何最好地调试这样的问题。

我尝试过的事情:

  • 监视pg_locks(并加入pg_class以获取上下文)。
  • 调查pageinspect.
  • 在本地手动复制,并在我确实有超级用户烫发的地方使用pgbench复制。到目前为止,我无法在本地复制该问题(我怀疑是由于数据集要小得多,但我不能确定)。

值得注意的是,当我看到这些问题时,CPU 利用率似乎很高(负载平均值为>1),因此上述本身可能没有任何问题,并且我认为这是由于系统资源不足的结果可用。我仍然想了解如何最好地调试它,以便我了解到底发生了什么。

关键是它是交易的ShareLock。

这意味着一个事务正在等待另一个事务提交/回滚,然后才能继续。它只是松散的"锁"。这里发生的事情是,PostgreSQL事务在启动时在其自己的事务ID上采用ExclusiveLock。其他想要等待它完成的事务可以尝试获取事务的 ShareLock,这将阻止,直到在提交/中止时释放 ExclusiveLock。它基本上是使用锁定机制作为实现事务间完成信号的便利。

当等待事务尝试为最近由等待的事务插入/修改的行INSERTUNIQUEPRIMARY KEY值时,通常会发生这种情况。等待事务在知道等待事务的结果之前无法继续 - 无论是提交还是回滚,如果已提交,目标行是否被删除/插入/其他任何内容。

这与错误消息中的内容一致。 进程"X"正在尝试插入到"my_test_table"中,并且必须等到进程"Y"提交xACT"z",以确定是否引发唯一的违规或是否可以继续。

很可能您在某种更新插入或队列处理系统中存在争用。如果您有一些函数/事务模式尝试插入到一个严重争用的表中,然后在提交之前执行大量其他耗时的工作,也会发生这种情况。

最新更新