Marcio Cunha

Banco travado? Como auditar locks e deadlocks no PostgreSQL

Aprenda a inspecionar a tabela pg_stat_activity para identificar transações travadas no PostgreSQL e evitar quedas graves na aplicação.

Marcio Cunha•5 min
Também disponível em:EnglishEspañol
Resumo
  • O monitoramento contínuo da tabela pg_stat_activity revela processos em espera antes que gerem indisponibilidade.
  • Conexões perdidas ou transações abandonadas costumam manter bloqueios ativos por tempo excessivo na base de dados.
  • Deadlocks ocorrem quando duas transações competem pelos mesmos recursos em ordens opostas e exigem intervenção externa.
  • Consultas bem estruturadas permitem rastrear quem está bloqueando e qual query está travando o sistema em tempo real.
  • Ajustar timeouts adequados e otimizar o fluxo de escrita previne interrupções catastróficas em ambientes de produção.

Por que o PostgreSQL trava repentinamente em produção?

Quando uma aplicação sofre uma queda repentina de desempenho ou para de responder, o banco de dados costuma ser o primeiro suspeito. Na maioria das vezes, o problema não é a falta de poder de processamento, mas sim uma fila invisível de transações competindo pelos mesmos dados. Na prática, isso significa que um comando simples ficou esperando indefinidamente porque outro processo segurou a chave de uma tabela sem soltar.

Para entender esse comportamento, precisamos olhar para o conceito de lock, que funciona como uma tranca em uma porta. Quando uma transação altera uma linha ou tabela, o PostgreSQL aplica um bloqueio para garantir que ninguém mais mexa naquuel dado até que o trabalho termine. Se outro processo tentar acessar o mesmo registro, ele precisará esperar pacientemente a liberação. O problema surge quando essa espera se torna eterna, criando um efeito cascata que paralisa todo o sistema.

Em ambientes de alta carga, identificar esses gargalos rapidamente é a diferença entre manter o negócio no ar ou enfrentar um apagão operacional. Para mitigar riscos e entender melhor a performance geral, muitos engenheiros combinam essa verificação com a rotina de avaliar consultas lentas, conforme detalhamos no guia sobre como auditar queries no PostgreSQL. Saber exatamente onde a fila emperra evita que conexões estoure o limite aceitável pelo servidor.

Como a tabela pg_stat_activity revela o que está acontecendo

O PostgreSQL possui ferramentas nativas fantásticas para inspecionar o seu próprio estado interno sem a necessidade de instalar pacotes externos complexos. A principal ferramenta de diagnóstico para esse cenário é a tabela de sistema chamada pg_stat_activity. Na prática, ela funciona como um painel de controle em tempo real que mostra exatamente o que cada conexão está executando naquele exato microssegundo.

Cada linha nessa tabela representa um processo ativo ou em espera no banco de dados. Podemos ver o usuário conectado, o endereço IP de origem, a aplicação cliente, o carimbo de data/hora do início da query e, o mais importante, o estado atual da transação. Se um processo estiver marcado com a condição de espera por bloqueio, saberemos imediatamente que ele encontrou uma barreira impeditiva criada por outra conexão no cluster.

Antes de investigar travas profundas, vale lembrar que muitos problemas de indisponibilidade nascem de limites mal configurados, um tema que abordamos extensivamente ao discutir como ajustar o pool de conexões e evitar erros. Um pool superlotado gera contenção desnecessária e abre margem para que locks persistan por muito mais tempo do que deveriam na infraestrutura.

Passo a passo para consultar transações travadas e bloqueios

Quando a aplicação começa a recusar novas requisições por timeout, precisamos agir com rapidez cirúrgica. O procedimento a seguir demonstra uma consulta SQL segura e altamente eficiente para listar os processos que estão segurando bloqueios e quem está preso na fila esperando por eles.

  1. Abra o seu cliente de banco de dados preferido conectado com um usuário superusuário ou com privilégios de monitoramento na instância do PostgreSQL.
  2. Copie a consulta de inspeção de bloqueios para identificar o identificador do processo bloqueador e do bloqueado.
  3. Execute o comando SQL abaixo no terminal do banco de dados para listar os rastros de travamento ativos.
SELECT bl.pid AS bloqueado_pid, us.usename AS bloqueado_usuario, k.query AS bloqueado_query, ex.pid AS bloqueador_pid, us2.usename AS bloqueador_usuario, ex.query AS bloqueador_query FROM pg_catalog.pg_locks bl JOIN pg_stat_activity k ON k.pid = bl.pid JOIN pg_catalog.pg_locks b ON b.locktype = bl.locktype AND b.database IS NOT DISTINCT FROM bl.database AND b.relation IS NOT DISTINCT FROM bl.relation AND b.page IS NOT DISTINCT FROM bl.page AND b.tuple IS NOT DISTINCT FROM bl.tuple AND b.virtualxid IS NOT DISTINCT FROM bl.virtualxid AND b.transactionid IS NOT DISTINCT FROM bl.transactionid AND b.classid IS NOT DISTINCT FROM bl.classid AND b.objid IS NOT DISTINCT FROM bl.objid AND b.objsubid IS NOT DISTINCT FROM bl.objsubid AND b.pid != bl.pid JOIN pg_stat_activity ex ON ex.pid = b.pid JOIN pg_user us ON us.usesysid = k.usesysid JOIN pg_user us2 ON us2.usesysid = ex.usesysid WHERE NOT bl.granted;

Esse comando cruza as tabelas de bloqueios ativos com a tabela de atividades do sistema para revelar exatamente quem está causando o engarrafamento. O resultado trará o código identificador chamado PID de quem está travando e de quem está travado, permitindo tomar uma decisão consciente sobre interromper ou não o processo.

Como resolver ou encerrar transações problemáticas com segurança

Depois de identificar qual processo está causando o estrangulamento na base de dados, surge a dúvida inevitável sobre o que fazer com ele. Em alguns casos, a transação travada é fruto de um relatório pesado que demorará mais alguns minutos, mas em outros cenários trata-se de um bug de código que nunca terminará sozinho. Na prática, decidir entre esperar ou derrubar a conexão exige avaliar o impacto para os usuários finais.

Se a decisão for encerrar a transação para restaurar a saúde do sistema, o PostgreSQL disponibiliza comandos específicos para cancelar ou eliminar o processo sem corromper os arquivos de dados. O comando pg_cancel_backend envia um sinal educado para que a query cancele sua execução atual e reverta a transação pendente. Caso o processo ignore o aviso, o comando pg_terminate_backend encerra a conexão de forma imediata e definitiva.

É fundamental usar essas ferramentas com cautela cirúrgica em servidores de produção. Derrubar uma transação no meio de uma gravação importante pode gerar um trabalho considerável de reversão, conhecido como rollback, que também consome recursos de disco e CPU. A regra de ouro é sempre verificar se a transação está travada por falha de lógica na aplicação antes de aplicar qualquer interrupção forçada. Para aprofundar esses conceitos na prática em produção, confira também nossa análise técnica sobre Como testar o circuito de power on da placa-mãe.

Considerações finais sobre prevenção de indisponibilidade

Auditar locks e deadlocks de forma preventiva é um hábito essencial para garantir a estabilidade de sistemas de grande porte em produção. Manter scripts de monitoramento prontos para uso em pg_stat_activity reduz drasticamente o tempo médio de resposta diante de incidentes críticos. O segredo para uma operação saudável reside na combinação de código limpo, tratamento adequado de exceções e limites rígidos de tempo limite para transações órfãs.

Investir tempo na educação da equipe de engenharia sobre como funcionam os bloqueios transacionais evita que gargalos recorrentes voltem a derrubar o serviço. Com uma estratégia clara de inspeção e resposta rápida, o banco de dados deixa de ser uma caixa-preta imprevisível e passa a ser um componente previsível, transparente e resiliente para o crescimento do negócio.