【问题标题】:Locks on postgres transactions锁定 postgres 事务
【发布时间】:2017-11-20 15:14:44
【问题描述】:

我正在对我的 node.js 应用程序进行负载测试。在某些时候,我达到了请求待处理的状态,我最好的猜测是由于锁定的事务。这是最后一条日志语句:

SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;

pg_lock 中,我有 4 行上面的查询分别是 GRANTED = truemode ExclusiveLock

我应该从哪里开始寻找错误? 如果在这个锁定请求中我提出了很多insertupdate 操作,那么隔离级别应该是REPEATABLE READ 吗? 有没有办法调试/处理这种情况? 是否有任何超时锁定机制,以便应用可以轻松/自动释放并且不会阻止进一步的请求?

附带问题(因为我没有直接寻找工具):是否有任何工具可以监控和发现这种情况? (我希望使用 Munin。)

我正在使用 nodejs 4.2.1 和 express 4.13.3,将 3.19.3 续集为 Postgres 9.4.1 ORM。

【问题讨论】:

  • 你检查 pg_stat_activity 和 pg_locks 了吗?你看到什么样的锁?那么 postgres 日志文件呢?你看到死锁了吗?
  • @FrankHeikens,我已经检查过pg_stat_activity 并没有发现任何可疑之处,但也许我不知道如何正确检查。当谈到锁定类型和查看日志文件时,我已经在我的问题中提到了它。 GRANTED = true 是否意味着没有死锁?如何正确验证?
  • @FrankHeikens 关于 cmets,我还可以找到:ERROR: could not serialize access due to concurrent update,这是我以前没见过的。当我在应用程序卡住时将其杀死时,日志中会出现 LOG: unexpected EOF on client connection with an open transaction 多次。
  • 如果没有代码和要求,很难判断问题出在哪里,但这是一个已知问题:postgresql.org/docs/9.4/static/… 根本原因:可重复读取事务在可重复读取事务之后无法修改或锁定其他事务更改的行开始了。
  • @kasiacode,你最终找到解决方法了吗?我遇到了类似的问题,目前处于死胡同。

标签: node.js postgresql sequelize.js


【解决方案1】:

欢迎来到 PostgreSQL 事务锁地狱 :)

您可能会花费大量时间试图找出锁定发生的确切位置以及原因。但它帮助您解决问题的可能性很小。

解决这种情况的一般方法如下:

  • 将事务大小保持在应用程序业务逻辑所需的最低限度。例如,避免相同类型的插入或更新,将它们替换为多行类似物,因为查询 IO 开销很大
  • 在仅执行修改数据的单个查询时不要使用事务,即避免不必要的事务。
  • 实施错误处理,可以确定事务锁定并提供重复尝试执行事务。记录此类重复将帮助您了解系统的弱点以及如何更好地重新设计它。

即使在设计精良的系统中,最后一步也经常成为必需品,不要让它吓到你 ;)

【讨论】:

  • 见鬼?为什么?交易可以帮助你,他们应该帮助你。但你确实需要一个好的设计。
  • 非常感谢您的回答。不幸的是,在目前的情况下它对我没有多大帮助。作为@FrankHeikens,我一直认为交易有很大帮助。你的意思是只有 Postgres 的交易是地狱还是一般?无论如何,阅读更多有关如何明智地在应用程序中设计事务的信息会很棒。
  • @kasiacode 我的意思是事务仅锁定(更正了我的答案)。
  • 我还真的需要一份关于如何使用 postgresql 设计事务的指南。我发现的那些正在走向高水平。
  • @vitaly-t 感谢您的回答,这对我很有帮助,我的问题是增加了许多不必要的交易。
【解决方案2】:

我遇到了类似的情况,我启动了 5 个并行事务来请求相同的更新锁,而第一个事务还继续进行需要更多 postgres 调用的工作。整个系统死锁,第一个事务在 pg_stat_activity 中被列为空闲事务,并被授予访问它在 pg_locks 中请求的所有锁的权限。

我认为正在发生的事情;

第一个事务获得了锁,然后完成了查询。在此之后,它会断开与 postgres 的连接。

以下 4 个事务分别打开一个连接并在锁上阻塞,该锁由第一个事务持有。

由于它们被阻塞,第一个事务开始执行,当它尝试连接到 postgres 进行查询时,它会死锁,因为 sequiezlize 已用完连接。

当我更改我的 squiezlize 初始化并添加更多连接到池中时,默认为 5,死锁消失了。

我不确定谁在使用第 5 个连接,或者由于某种原因默认值恰好是 4 而不是 5,但似乎仍然勾选了所有框。

另一种解决方案是在 postgres 中使用 NOWAIT 选项,因此在请求锁定但未获得锁定时事务中止,具体取决于您的用例。

如果其他人遇到同样的问题,希望对您有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-07
    • 2012-07-23
    • 2011-12-30
    相关资源
    最近更新 更多