Lock:tuple
在后端进程等待获取元组锁定时,会发生 Lock:tuple
事件。
支持的引擎版本
Aurora PostgreSQL 的所有版本均支持此等待事件信息。
上下文
事件 Lock:tuple
表示一个后端正在等待获取元组上的锁定,而另一个后端在同一个元组上保持冲突锁定。下表说明了会话生成 Lock:tuple
事件的场景。
Time |
会话 1 |
会话 2 |
会话 3 |
---|---|---|---|
t1 |
开始事务。 |
||
t2 |
更新第 1 行。 |
||
t3 |
更新第 1 行。会话获取元组上的独占锁定,然后等待会话 1 通过提交或回滚来释放锁。 |
||
t4 |
更新第 1 行。会话等待会话 2 才能释放元组上的独占锁定。 |
或者您可以使用基准测试工具 pgbench
来模拟此等待事件。配置大量并发会话以使用自定义 SQL 文件更新表中的同一行。
要了解冲突锁模式的更多信息,请参阅 PostgreSQL 文档中的显式锁定pgbench
的更多信息,请参阅 PostgreSQL 文档中的 pgbench
等待次数增加的可能原因
当此事件的发生率超过正常(可能表示性能问题)时,典型原因包括以下几点:
-
大量并发会话试图通过运行
UPDATE
或DELETE
语句获取相同元组的冲突锁定。 -
高度并发的会话正在使用
FOR UPDATE
或FOR 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 中的锁定依赖项信息Lock:tuple
事件,请使用 Aurora 函数 aurora_stat_backend_waits
。
以下示例查询所有会话,并对 tuple
进行筛选,通过 wait_time
进行排序。
--AURORA_STAT_BACKEND_WAITS SELECT a.pid, a.usename, a.app_name, a.current_query, a.current_wait_type, a.current_wait_event, a.current_state, wt.type_name AS wait_type, we.event_name AS wait_event, a.waits, a.wait_time FROM (SELECT pid, usename, left(application_name,16) AS app_name, coalesce(wait_event_type,'CPU') AS current_wait_type, coalesce(wait_event,'CPU') AS current_wait_event, state AS current_state, left(query,80) as current_query, (aurora_stat_backend_waits(pid)).* FROM pg_stat_activity WHERE pid <> pg_backend_pid() AND usename<>'rdsadmin') a NATURAL JOIN aurora_stat_wait_type() wt NATURAL JOIN aurora_stat_wait_event() we WHERE we.event_name = 'tuple' ORDER BY a.wait_time; pid | usename | app_name | current_query | current_wait_type | current_wait_event | current_state | wait_type | wait_event | waits | wait_time -------+---------+----------+------------------------------------------------+-------------------+--------------------+---------------+-----------+------------+-------+----------- 32136 | sys | psql | /*session3*/ update tab set col=1 where col=1; | Lock | tuple | active | Lock | tuple | 1 | 1000018 11999 | sys | psql | /*session4*/ update tab set col=1 where col=1; | Lock | tuple | active | Lock | tuple | 1 | 1000024
在并发性高时降低并发性
Lock:tuple
事件可能会不断发生,特别是在繁忙的工作负载时间。在这种情况下,考虑降低非常繁忙的行的高并发率。通常,只有几个行控制队列或布尔逻辑,这使得这些行非常繁忙。
您可以根据业务需求、应用程序逻辑和工作负载类型使用不同的方法来降低并发性。例如,您可以执行以下操作:
-
重新设计表和数据逻辑以降低高并发性。
-
更改应用程序逻辑以降低行级别的高并发性。
-
使用行级锁定利用和重新设计查询。
-
使用具有重试操作的
NOWAIT
子句。 -
考虑使用乐观和混合锁定逻辑并发控制。
-
考虑更改数据库隔离级别。
排查瓶颈
当出现诸如 CPU 匮乏或 Amazon EBS 带宽的最大使用率的瓶颈时,可能会发生 Lock:tuple
。要减少瓶颈,请考虑以下方法:
-
纵向扩展您的实例类类型。
-
优化资源密集型查询。
-
更改应用程序逻辑。
-
存档很少访问的数据。