LWLock:SubtransSLRU - Amazon Aurora

LWLock:SubtransSLRU

Los eventos de espera LWLock:SubtransSLRU y LWLock:SubtransBuffer indican que una sesión está esperando para acceder a la caché simple de uso menos reciente (SLRU) para la información de subtransacciones. Esto ocurre al determinar la visibilidad de las transacciones y las relaciones entre principales y secundarios.

  • LWLock:SubtransSLRU: un proceso está esperando para acceder a la caché simple de uso menos reciente (SLRU) para una subtransacción. En Aurora PostgreSQL 12.22 y versiones anteriores, este evento de espera se llama SubtransControlLock.

  • LWLock:SubtransBuffer: un proceso está esperando la E/S en un búfer simple de uso menos reciente (SLRU) para una subtransacción. En Aurora PostgreSQL 12.22 y versiones anteriores, este evento de espera se llama subtrans.

Versiones del motor admitidas

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

Contexto

Descripción de las subtransacciones: una subtransacción es una transacción dentro de una transacción en PostgreSQL. También se conoce como transacción anidada.

Por lo general, las subtransacciones se crean cuando se utiliza:

  • SAVEPOINTComandos de

  • Bloques de excepciones (BEGIN/EXCEPTION/END)

Las subtransacciones le permiten revertir partes de una transacción sin que ello afecte a toda la transacción. Esto le brinda un control minucioso sobre la administración de transacciones.

Detalles de implementación: PostgreSQL implementa subtransacciones como estructuras anidadas dentro de las transacciones principales. Cada subtransacción recibe su propio ID de transacción.

Aspectos de implementación claves:

  • Los ID de las transacciones se rastrean en pg_xact

  • Las relaciones principal-secundario se almacenan en el subdirectorio pg_subtrans en PGDATA

  • Cada sesión de base de datos puede mantener hasta 64 subtransacciones activas

  • Si se supera este límite se produce un desbordamiento de subtransacciones, lo que requiere acceder a la caché simple de uso menos reciente (SLRU) para la información de subtransacciones

Causas probables del aumento de las esperas

Entre las causas más comunes de la contención de SLRU en las subtransacciones se incluyen:

  • Uso excesivo del manejo de SAVEPOINT y EXCEPTION: los procedimientos PL/pgSQL con controladores EXCEPTION crean automáticamente puntos de almacenamiento implícitos, independientemente de si se producen o no excepciones. Cada SAVEPOINT inicia una nueva subtransacción. Cuando una sola transacción acumula más de 64 subtransacciones, desencadena un desbordamiento de SLRU de subtransacciones.

  • Configuraciones de controladores y ORM: el uso de SAVEPOINT puede ser explícito en el código de la aplicación o implícito en las configuraciones de los controladores. Muchas de las herramientas ORM y los marcos de aplicaciones más utilizados admiten transacciones anidadas de forma nativa. Estos son algunos ejemplos comunes:

    • El parámetro del controlador JDBC autosave, si está establecido en always o conservative, genera puntos de almacenamiento antes de cada consulta.

    • Definiciones de transacciones de Spring Framework cuando se establece en propagation_nested.

    • Registros de seguimiento cuando requires_new: true está configurado.

    • SQLAlchemy cuando session.begin_nested se usa.

    • Django cuando se usan bloques de atomic() anidados.

    • GORM cuando se usa Savepoint.

    • psqlODBC cuando la configuración por reversión se establece en la reversión por instrucción (por ejemplo, PROTOCOL=7.4-2).

  • Cargas de trabajo simultáneas altas con transacciones y subtransacciones de larga duración: cuando se produce un desbordamiento de la SLRU de subtransacciones durante cargas de trabajo simultáneas altas y transacciones y subtransacciones de larga duración, PostgreSQL experimenta una mayor contención. Esto se manifiesta como eventos de espera elevados para bloqueos LWLock:SubtransBuffer y LWLock:SubtransSLRU.

Acciones

Recomendamos diferentes acciones en función de las causas del evento de espera. Algunas acciones proporcionan un alivio inmediato, mientras que otras requieren una investigación y una corrección a largo plazo.

Supervisión del uso de subtransacciones

Para las versiones 16.1 y posteriores de PostgreSQL, utilice la siguiente consulta para supervisar los recuentos de subtransacciones y el estado de desbordamiento por backend. Esta consulta combina las estadísticas del backend con la información de la actividad para mostrar qué procesos utilizan subtransacciones:

SELECT a.pid, usename, query, state, wait_event_type, wait_event, subxact_count, subxact_overflowed FROM (SELECT id, pg_stat_get_backend_pid(id) pid, subxact_count, subxact_overflowed FROM pg_stat_get_backend_idset() id JOIN LATERAL pg_stat_get_backend_subxact(id) AS s ON true ) a JOIN pg_stat_activity b ON a.pid = b.pid;

Para las versiones 13.3 y posteriores de PostgreSQL, supervise la vista pg_stat_slru para comprobar la presión de la caché de las subtransacciones. La siguiente consulta SQL recupera las estadísticas de la caché de la SLRU para el componente Subtrans:

SELECT * FROM pg_stat_slru WHERE name = 'Subtrans';

Un valor blks_read que aumenta de forma coherente indica el acceso frecuente al disco para las subtransacciones no almacenadas en caché, lo que indica una posible presión en la memoria caché de la SLRU.

Configuración de los parámetros de memoria

Para PostgreSQL 17.1 y versiones posteriores, puede configurar el tamaño de la caché de SLRU de la subtransacción mediante el parámetro subtransaction_buffers. En el siguiente ejemplo de configuración, se muestra cómo establecer el parámetro de búfer de subtransacciones:

subtransaction_buffers = 128

Este parámetro especifica la cantidad de memoria compartida que se utiliza para almacenar en caché el contenido de las subtransacciones (pg_subtrans). Si se especifica sin unidades, el valor representa bloques de BLCKSZ bytes, normalmente de 8 KB cada uno. Por ejemplo, si se establece el valor en 128, se asigna 1 MB (128 * 8 KB) de memoria para la caché de subtransacciones.

nota

Puede establecer este parámetro por clúster para que todas las instancias se mantengan coherentes. Pruebe y ajuste el valor para que se adapte a los requisitos de carga de trabajo específicos y a la clase de instancia. Debe reiniciar la instancia de escritor para que los cambios de parámetro tengan efecto.

Acciones a largo plazo

  • Examine el código y las configuraciones de la aplicación: revise las configuraciones del código de la aplicación y del controlador de la base de datos para ver el uso explícito e implícito de SAVEPOINT y el uso de subtransacciones en general. Identifique las transacciones que podrían generar más de 64 subtransacciones.

  • Reduzca el uso de puntos de almacenamiento: minimice el uso de puntos de almacenamiento en las transacciones:

    • Revise los procedimientos y las funciones de PL/pgSQL con bloques EXCEPTION. Los bloques EXCEPTION crean automáticamente puntos de almacenamiento implícitos, que pueden contribuir al desbordamiento de las subtransacciones. Cada cláusula EXCEPTION crea una subtransacción, independientemente de si realmente se produce una excepción durante la ejecución.

      Ejemplo 1: Uso problemático del bloque EXCEPTION

      En el siguiente ejemplo de código, se muestra el uso problemático del bloque EXCEPTION que crea varias subtransacciones:

      CREATE OR REPLACE FUNCTION process_user_data() RETURNS void AS $$ DECLARE user_record RECORD; BEGIN FOR user_record IN SELECT * FROM users LOOP BEGIN -- This creates a subtransaction for each iteration INSERT INTO user_audit (user_id, action, timestamp) VALUES (user_record.id, 'processed', NOW()); UPDATE users SET last_processed = NOW() WHERE id = user_record.id; EXCEPTION WHEN unique_violation THEN -- Handle duplicate audit entries UPDATE user_audit SET timestamp = NOW() WHERE user_id = user_record.id AND action = 'processed'; END; END LOOP; END; $$ LANGUAGE plpgsql;

      El ejemplo de código mejorado siguiente reduce el uso de subtransacciones mediante el uso de UPSERT en lugar del manejo de excepciones:

      CREATE OR REPLACE FUNCTION process_user_data() RETURNS void AS $$ DECLARE user_record RECORD; BEGIN FOR user_record IN SELECT * FROM users LOOP -- Use UPSERT to avoid exception handling INSERT INTO user_audit (user_id, action, timestamp) VALUES (user_record.id, 'processed', NOW()) ON CONFLICT (user_id, action) DO UPDATE SET timestamp = NOW(); UPDATE users SET last_processed = NOW() WHERE id = user_record.id; END LOOP; END; $$ LANGUAGE plpgsql;

      Ejemplo 2: Controlador de excepciones STRICT

      En el ejemplo de código siguiente, se muestra un manejo problemático de EXCEPTION con NO_DATA_FOUND:

      CREATE OR REPLACE FUNCTION get_user_email(p_user_id INTEGER) RETURNS TEXT AS $$ DECLARE user_email TEXT; BEGIN BEGIN -- STRICT causes an exception if no rows or multiple rows found SELECT email INTO STRICT user_email FROM users WHERE id = p_user_id; RETURN user_email; EXCEPTION WHEN NO_DATA_FOUND THEN RETURN 'Email not found'; END; END; $$ LANGUAGE plpgsql;

      El ejemplo de código mejorado siguiente evita subtransacciones mediante el uso de IF NOT FOUND en lugar del manejo de excepciones:

      CREATE OR REPLACE FUNCTION get_user_email(p_user_id INTEGER) RETURNS TEXT AS $$ DECLARE user_email TEXT; BEGIN SELECT email INTO user_email FROM users WHERE id = p_user_id; IF NOT FOUND THEN RETURN 'Email not found'; ELSE RETURN user_email; END IF; END; $$ LANGUAGE plpgsql;
    • Controlador JDBC: el parámetro autosave, si está establecido en always o conservative, genera puntos de almacenamiento antes de cada consulta. Evalúe si la configuración de never sería aceptable para la aplicación.

    • Controlador ODBC de PostgreSQL (psqlODBC): la configuración del nivel de reversión (para la reversión por instrucción) crea puntos de almacenamiento implícitos para habilitar la funcionalidad de reversión de instrucciones. Evalúe si el nivel de la transacción o sin reversión sería aceptable para la aplicación.

    • Examen de las configuraciones de transacciones de ORM

    • Consideración de estrategias alternativas de manejo de errores que no requieran puntos de almacenamiento

  • Optimización del diseño de las transacciones: reestructure las transacciones para evitar el anidamiento excesivo y reducir la probabilidad de que se produzcan desbordamientos de las subtransacciones.

  • Reduzca las transacciones de larga duración: las transacciones de larga duración pueden agravar los problemas relacionados con las subtransacciones al conservar la información de las subtransacciones durante más tiempo. Supervise las métricas de información de rendimiento y configure el parámetro idle_in_transaction_session_timeout para terminar automáticamente las transacciones inactivas.

  • Supervise las métricas de información de rendimiento: realice un seguimiento de las métricas, incluido idle_in_transaction_count (número de sesiones inactivas en estado de transacción) y idle_in_transaction_max_time (duración de la transacción inactiva más prolongada) para detectar transacciones de larga duración.

  • Configure idle_in_transaction_session_timeout: defina este parámetro en el grupo de parámetros para terminar automáticamente las transacciones inactivas después de un periodo especificado.

  • Supervisión proactiva: supervise los eventos de espera de alta frecuencia LWLock:SubtransBuffer y LWLock:SubtransSLRU para detectar conflictos relacionados con las subtransacciones antes de que se conviertan en críticos.