LWLock:SubtransSLRU
Os eventos de espera LWLock:SubtransSLRU e LWLock:SubtransBuffer indicam que uma sessão está aguardando para acessar o cache simples utilizado com menor frequência (SLRU) para informações de subtransação. Isso ocorre ao determinar a visibilidade da transação e os relacionamentos pai-filho.
-
LWLock:SubtransSLRU: um processo está aguardando para acessar o cache simples menos utilizado recentemente (SLRU) para uma subtransação. No Aurora PostgreSQL 12.22 e versões anteriores, esse evento de espera é chamadoSubtransControlLock. -
LWLock:SubtransBuffer: um processo está aguardando a E/S em um buffer simples menos utilizado recentemente (SLRU) para uma subtransação. No Aurora PostgreSQL 12.22 e versões anteriores, esse evento de espera é chamadosubtrans.
Versões compatíveis do mecanismo
As informações sobre esse evento de espera são aceitas em todas as versões do Aurora PostgreSQL.
Contexto
Noções básicas sobre subtransações: subtransação é uma transação dentro de uma transação no PostgreSQL. Também é conhecida como transação aninhada.
Normalmente, as subtransações são criadas quando você usa:
-
SAVEPOINTComandos do do -
Blocos de exceção (
BEGIN/EXCEPTION/END)
As subtransações permitem reverter partes de uma transação sem afetar toda ela. Isso oferece controle refinado sobre o gerenciamento de transações.
Detalhes da implementação: o PostgreSQL implementa subtransações como estruturas aninhadas nas transações principais. Cada subtransação recebe seu próprio ID.
Principais aspectos de implementação:
-
Os IDs de transação são monitorados em
pg_xact. -
Os relacionamentos pai-filho são armazenados no subdiretório
pg_subtransemPGDATA. -
Cada sessão do banco de dados pode manter até
64subtransações ativas. -
Exceder esse limite causa estouro de subtransação, o que requer acesso ao cache simples utilizado com menor frequência (SLRU) para informações de subtransação.
Possíveis causas do maior número de esperas
As causas comuns de contenção de SLRU por subtransação são as seguintes:
-
Uso excessivo do tratamento de SAVEPOINT e EXCEPTION: os procedimentos PL/pgSQL com manipuladores
EXCEPTIONcriam automaticamente pontos de salvamento implícitos, independentemente da ocorrência de exceções. CadaSAVEPOINTinicia uma nova subtransação. Quando uma única transação acumula mais de 64 subtransações, ela aciona um estouro de SLRU de subtransação. -
Configurações de driver e ORM: o uso de
SAVEPOINTpode ser explícito no código da aplicação ou implícito nas configurações do driver. Muitas ferramentas de ORM e frameworks de aplicações geralmente usadas comportam transações aninhadas de forma nativa. Veja aqui alguns exemplos comuns:-
O parâmetro do driver JDBC
autosave, se definido comoalwaysouconservative, gera pontos de salvamento antes de cada consulta. -
Definições de transação do Spring Framework quando configuradas como
propagation_nested. -
Trilhos quando
requires_new: trueestá definido. -
SQLAlchemy quando
session.begin_nestedé usado. -
Django quando blocos
atomic()aninhados são usados. -
GORM quando
Savepointé usado. -
psqlODBC quando a configuração do nível de reversão é definida como reversão em nível de instrução (por exemplo,
PROTOCOL=7.4-2).
-
-
Altas workloads simultâneas com transações e subtransações de longa execução: quando ocorre um estouro de SLRU de subtransação durante workloads altamente simultâneas e transações e subtransações de longa execução, o PostgreSQL sofre uma maior contenção. Isso se manifesta como eventos de espera elevados para bloqueios
LWLock:SubtransBuffereLWLock:SubtransSLRU.
Ações
Recomenda-se ações distintas, dependendo dos motivos do evento de espera. Algumas ações fornecem alívio imediato, enquanto outras exigem investigação e correção no longo prazo.
Monitorar o uso de subtransações
Para as versões 16.1 e posteriores do PostgreSQL, use a consulta a seguir para monitorar as contagens de subtransações e o status de estouro por backend. Essa consulta une estatísticas de backend com informações de atividades para mostrar quais processos estão usando subtransações:
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 as versões 13.3 e posteriores do PostgreSQL, monitore a visualização pg_stat_slru da pressão do cache de subtransação. A consulta SQL a seguir recupera estatísticas de cache SLRU para o componente Subtrans:
SELECT * FROM pg_stat_slru WHERE name = 'Subtrans';
Um valor blks_read consistentemente crescente indica acesso frequente ao disco para subtransações não armazenadas em cache, sinalizando uma possível pressão no cache de SLRU.
Configurar parâmetros de memória
Para o PostgreSQL 17.1 e versões posteriores, é possível configurar o tamanho do cache de SLRU de subtransações usando o parâmetro subtransaction_buffers. O seguinte exemplo de configuração mostra como definir o parâmetro de buffer de subtransações:
subtransaction_buffers = 128
Esse parâmetro especifica a quantidade de memória compartilhada utilizada para armazenar conteúdo de subtransação (pg_subtrans). Quando especificado sem unidades, o valor representa blocos de BLCKSZ bytes, normalmente 8 KB cada. Por exemplo, definir o valor como 128 aloca 1 MB (128 x 8 kB) de memória para o cache de subtransações.
nota
É possível definir esse parâmetro em nível de cluster para que todas as instâncias permaneçam consistentes. Teste e ajuste o valor para melhor atender aos requisitos específicos da workload e à classe de instância. É necessário reinicializar a instância do gravador para que a alteração do parâmetro tenha efeito.
Ações de longo prazo
-
Examinar o código e as configurações da aplicação: analise as configurações do código da aplicação e do driver do banco de dados quanto ao uso explícito e implícito de
SAVEPOINTe ao uso de subtransações em geral. Identifique transações que podem geram mais de 64 subtransações. -
Reduzir o uso de pontos de salvamento: minimize o uso de pontos de salvamento nas transações:
-
Analise os procedimentos PL/pgSQL e funções com blocos EXCEPTION. Os blocos EXCEPTION criam automaticamente pontos de salvamento implícitos, que podem contribuir para o estouro de subtransações. Cada cláusula EXCEPTION cria uma subtransação, independentemente de uma exceção realmente ocorrer durante a execução.
Exemplo 1: uso problemático do bloco EXCEPTION
O exemplo de código a seguir mostra o uso problemático do bloco EXCEPTION que cria várias subtransações:
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;O exemplo de código aprimorado a seguir reduz o uso de subtransações usando UPSERT em vez do tratamento de exceções:
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;Exemplo 2: manipulador de exceções STRICT
O exemplo de código a seguir mostra o tratamento problemático de EXCEPTION com 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;O exemplo de código aprimorado a seguir evita subtransações usando IF NOT FOUND em vez do tratamento de exceções:
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; -
Driver JDBC: o parâmetro
autosave, se definido comoalwaysouconservative, gera pontos de salvamento antes de cada consulta. Avalie se a configuraçãoneverseria aceitável para sua aplicação. -
Driver ODBC do PostgreSQL (psqlODBC): a configuração em nível de reversão (para reversão em nível da instrução) cria pontos de salvamento implícitos para habilitar a funcionalidade de reversão da instrução. Avalie se a reversão em nível de transação ou nenhuma reversão seria aceitável para sua aplicação.
-
Examinar as configurações de transações do ORM
-
Pense nas estratégias alternativas de tratamento de erros que não exijam pontos de salvamento
-
-
Otimizar o design da transação: reestruture as transações para evitar o agrupamento excessivo e reduzir a probabilidade de condições de estouro de subtransações.
-
Reduzir as transações de longa duração: as transações de longa duração podem agravar os problemas com subtransações ao reter as informações delas por mais tempo. Monitore as métricas do Insights de Performance e configure o parâmetro
idle_in_transaction_session_timeoutpara encerrar automaticamente as transações ociosas. -
Monitorar as métricas do Insights de Performance: acompanhe métricas, incluindo
idle_in_transaction_count(número de sessões inativas no estado da transação) eidle_in_transaction_max_time(duração da transação ociosa mais longa) para detectar transações de longa duração. -
Configurar
idle_in_transaction_session_timeout: defina esse parâmetro em seu grupo de parâmetros para encerrar automaticamente transações ociosas após um período especificado. -
Monitoramento proativo: monitore altas ocorrências de eventos de espera
LWLock:SubtransBuffereLWLock:SubtransSLRUpara detectar contenções relacionadas a subtransações antes que elas se tornem críticas.