Lock:tuple - Amazon Relational Database Service

Lock:tuple

El evento Lock:tuple se produce cuando un proceso backend espera adquirir un bloqueo sobre una tupla.

Versiones del motor admitidas

Esta información de eventos de espera es compatible con todas las versiones de RDS para PostgreSQL.

Contexto

El evento Lock:tuple indica que un backend espera adquirir un bloqueo sobre una tupla mientras otro backend mantiene un bloqueo conflictivo sobre la misma tupla. La siguiente tabla ilustra un escenario en el que las sesiones generan el evento Lock:tuple.

Time

Sesión 1

Sesión 2

Sesión 3

t1

Inicia una transacción.

t2

Actualiza la fila 1.

t3

Actualiza la fila 1. La sesión adquiere un bloqueo exclusivo sobre la tupla y luego espera a que la sesión 1 libere el bloqueo mediante la confirmación o reversión.

t4

Actualiza la fila 1. La sesión espera a que la sesión 2 libere el bloqueo exclusivo en la tupla.

También puede simular este evento de espera con la herramienta de punto de referencia pgbench. Configure un alto número de sesiones concurrentes para actualizar la misma fila en una tabla con un archivo SQL personalizado.

Para obtener más información sobre los modos de bloqueo conflictivos, consulte E en la documentación de PostgreSQL. Para más información sobre pgbench, consulte pgbench en la documentación de PostgreSQL.

Causas probables del aumento de las esperas

Cuando este evento aparece más de lo normal, lo que posiblemente indica un problema de rendimiento, las causas típicas son las siguientes:

  • Un gran número de sesiones concurrentes están intentando adquirir un bloqueo conflictivo para la misma tupla al ejecutar instrucciones UPDATE o DELETE.

  • Las sesiones altamente concurrentes se encuentran en ejecución con una instrucción SELECT que utiliza los modos de bloqueo FOR UPDATE o FOR NO KEY UPDATE.

  • Varios factores hacen que la aplicación o los grupos de conexión abran más sesiones para ejecutar las mismas operaciones. A medida que nuevas sesiones intentan modificar las mismas filas, la carga de la base de datos puede aumentar y puede aparecer Lock:tuple.

Para más información, consulte Row-Level Locks en la documentación de PostgreSQL.

Acciones

Recomendamos diferentes acciones en función de las causas del evento de espera.

Investigue la lógica de su aplicación

Verifique si una sesión del bloqueador se encuentra en el estado idle in transaction por mucho tiempo. Si es así, considere la posibilidad de finalizar la sesión del bloqueador como una solución a corto plazo. Puede utilizar la función pg_terminate_backend. Para más información sobre esta función, consulte Server Signaling Functions en la documentación de PostgreSQL.

Para una solución a largo plazo, haga lo siguiente:

  • Ajuste la lógica de la aplicación.

  • Utilice el parámetro idle_in_transaction_session_timeout. Este parámetro finaliza cualquier sesión con una transacción abierta que haya estado inactiva durante más tiempo del especificado. Para más información, consulte Client Connection Defaults en la documentación de PostgreSQL.

  • Utilice la confirmación automática en la medida de lo posible. Para más información, consulte SET AUTOCOMMIT en la documentación de PostgreSQL.

Encontrar la sesión bloqueadora

Mientras se produce el evento de espera Lock:tuple, identifique el bloqueador y la sesión bloqueada mediante la búsqueda de los bloqueos que dependen unos de otros. Para más información, consulte la Información sobre dependencia de bloqueos en el wiki de PostgreSQL.

El siguiente ejemplo muestra todas las sesiones, con un filtro tuple y ordenadas por 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;

Reducir la concurrencia cuando es alta

El evento Lock:tuple puede producirse de manera frecuente, especialmente en un momento de carga de trabajo elevada. En esta situación, considere reducir la alta concurrencia para las filas muy ocupadas. A menudo, solo unas pocas filas controlan una cola o la lógica booleana, lo que hace que estas filas estén muy ocupadas.

Puede reducir la concurrencia mediante el uso de diferentes enfoques basados en los requisitos de la empresa, lógica de la aplicación y tipo de carga de trabajo. Por ejemplo, puede hacer lo siguiente:

  • Rediseñar la lógica de la tabla y los datos para reducir la alta concurrencia.

  • Cambiar la lógica de la aplicación para reducir la alta concurrencia entre filas.

  • Aprovechar y rediseñar las consultas con bloqueos entre filas.

  • Utilizar la cláusula NOWAIT con operaciones de reintento.

  • Considerar el uso de control de concurrencia optimista y de lógica de bloqueo híbrida.

  • Considerar la posibilidad de cambiar el nivel de aislamiento de la base de datos.

Solucionar los cuellos de botella

La Lock:tuple producirse con cuellos de botella, como el agotamiento de la CPU o el uso máximo del ancho de banda de Amazon EBS. Para reducir los cuellos de botella, considere los siguientes enfoques:

  • Escalar verticalmente el tipo de clase de instancia.

  • Optimizar las consultas que consumen muchos recursos.

  • Cambiar la lógica de la aplicación.

  • Archivar los datos a los que rara vez se accede.