Lock:tuple - Amazon Relational Database Service
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

Lock:tuple

在后端进程等待获取元组锁定时,会发生 Lock:tuple 事件。

支持的引擎版本

RDS for PostgreSQL 的所有版本均支持此等待事件信息。

上下文

事件 Lock:tuple 表示一个后端正在等待获取元组上的锁定,而另一个后端在同一个元组上保持冲突锁定。下表说明了会话生成 Lock:tuple 事件的场景。

Time

会话 1

会话 2

会话 3

t1

开始事务。

t2

更新第 1 行。

t3

更新第 1 行。会话获取元组上的独占锁定,然后等待会话 1 通过提交或回滚来释放锁。

t4

更新第 1 行。会话等待会话 2 才能释放元组上的独占锁定。

或者您可以使用基准测试工具 pgbench 来模拟此等待事件。配置大量并发会话以使用自定义 SQL 文件更新表中的同一行。

要了解冲突锁模式的更多信息,请参阅 PostgreSQL 文档中的显式锁定。要了解有关 pgbench 的更多信息,请参阅 PostgreSQL 文档中的 pgbench

等待次数增加的可能原因

当此事件的发生率超过正常(可能表示性能问题)时,典型原因包括以下几点:

  • 大量并发会话试图通过运行 UPDATEDELETE 语句获取相同元组的冲突锁定。

  • 高度并发的会话正在使用 FOR UPDATEFOR NO KEY UPDATE 锁定模式运行 SELECT 语句。

  • 各种因素促使应用程序或连接池打开更多会话以执行相同的操作。由于新会话正在尝试修改相同的行,数据库负载可能会激增,Lock:tuple 可以出现。

有关更多信息,请参阅 PostgreSQL 文档中的行级锁定

操作

根据等待事件的原因,我们建议采取不同的操作。

调查应用程序逻辑

了解阻止器会话是否已经处于 idle in transaction 状态很长一段时间。如果是这样,请考虑结束阻止器会话,作为短期解决方案。您可以使用 pg_terminate_backend 函数。有关此函数的更多信息,请参阅 PostgreSQL 文档中的服务器信号函数

要获得长期解决方案,请执行以下操作:

  • 调整应用程序逻辑。

  • 使用 idle_in_transaction_session_timeout 参数。此参数可结束空闲时间超过指定时间的已打开事务的任何会话。有关更多信息,请参阅 PostgreSQL 文档中的客户端连接原定设置

  • 尽可能多地使用自动提交。有关更多信息,请参阅 PostgreSQL 文档中的 SET AUTOCOMMIT

查找阻止器会话

Lock:tuple 等待事件发生时,通过找出哪些锁相互依赖来识别阻止器和已阻止的会话。有关更多信息,请参阅 PostgreSQL wiki 中的锁定依赖项信息

以下示例查询所有会话,并对 tuple 进行筛选,通过 wait_time 进行排序。

SELECT blocked_locks.pid AS blocked_pid, blocking_locks.pid AS blocking_pid, blocked_activity.usename AS blocked_user, blocking_activity.usename AS blocking_user, now() - blocked_activity.xact_start AS blocked_transaction_duration, now() - blocking_activity.xact_start AS blocking_transaction_duration, concat(blocked_activity.wait_event_type,':',blocked_activity.wait_event) AS blocked_wait_event, concat(blocking_activity.wait_event_type,':',blocking_activity.wait_event) AS blocking_wait_event, blocked_activity.state AS blocked_state, blocking_activity.state AS blocking_state, blocked_locks.locktype AS blocked_locktype, blocking_locks.locktype AS blocking_locktype, blocked_activity.query AS blocked_statement, blocking_activity.query AS blocking_statement FROM pg_catalog.pg_locks blocked_locks JOIN pg_catalog.pg_stat_activity blocked_activity ON blocked_activity.pid = blocked_locks.pid JOIN pg_catalog.pg_locks blocking_locks ON blocking_locks.locktype = blocked_locks.locktype AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid AND blocking_locks.pid != blocked_locks.pid JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid WHERE NOT blocked_locks.GRANTED;

在并发性高时降低并发性

Lock:tuple 事件可能会不断发生,特别是在繁忙的工作负载时间。在这种情况下,考虑降低非常繁忙的行的高并发率。通常,只有几个行控制队列或布尔逻辑,这使得这些行非常繁忙。

您可以根据业务需求、应用程序逻辑和工作负载类型使用不同的方法来降低并发性。例如,您可以执行以下操作:

  • 重新设计表和数据逻辑以降低高并发性。

  • 更改应用程序逻辑以降低行级别的高并发性。

  • 使用行级锁定利用和重新设计查询。

  • 使用具有重试操作的 NOWAIT 子句。

  • 考虑使用乐观和混合锁定逻辑并发控制。

  • 考虑更改数据库隔离级别。

排查瓶颈

当出现诸如 CPU 匮乏或 Amazon EBS 带宽的最大使用率的瓶颈时,可能会发生 Lock:tuple。要减少瓶颈,请考虑以下方法:

  • 纵向扩展您的实例类类型。

  • 优化资源密集型查询。

  • 更改应用程序逻辑。

  • 存档很少访问的数据。