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 llamaSubtransControlLock. -
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 llamasubtrans.
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_subtransenPGDATA -
Cada sesión de base de datos puede mantener hasta
64subtransacciones 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
EXCEPTIONcrean automáticamente puntos de almacenamiento implícitos, independientemente de si se producen o no excepciones. CadaSAVEPOINTinicia 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
SAVEPOINTpuede 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 enalwaysoconservative, 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: trueestá configurado. -
SQLAlchemy cuando
session.begin_nestedse 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:SubtransBufferyLWLock: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.
Temas
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
SAVEPOINTy 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 enalwaysoconservative, genera puntos de almacenamiento antes de cada consulta. Evalúe si la configuración deneverserí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_timeoutpara 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) yidle_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:SubtransBufferyLWLock:SubtransSLRUpara detectar conflictos relacionados con las subtransacciones antes de que se conviertan en críticos.