
Mitigando Bloat de WAL por Replication Slot no Postgres
Resolva o bloat de WAL por replication slot no Postgres antes que o disco encha. Use max_slot_wal_keep_size e fail-safes para proteger a alta disponibilidade.
Mitigando Bloat de WAL por Replication Slot no Postgres
O bloat de WAL por replication slot no Postgres gerou um incidente crítico de severidade 1 às 3h15 da madrugada, quando a utilização de disco da instância primária atingiu 98%, ameaçando a paralisação completa do banco transacional. Os consumidores downstream no pipeline de captura de dados de mudança (CDC) travaram após uma alteração de esquema não tratada, mas o replication slot lógico permaneceu retendo o Log Sequence Number (LSN) de reinicialização. Como o PostgreSQL garante a retenção de segmentos de WAL até que todos os slots confirmem o consumo, o motor acumulou centenas de gigabytes de arquivos em pg_wal, ameaçando o core OLTP. Resolver essa falha exige proteções rígidas de retenção, monitoramento contínuo de lag de LSN e políticas automatizadas de invalidação de slots.
Por Que Replication Slots Lógicos Causam Crescimento Indesejado de WAL
A decodificação lógica no PostgreSQL depende de replication slots para fornecer aos consumidores externos um fluxo contínuo de mutações em nível de linha. Diferente da replicação física, que transmite blocos de disco brutos diretamente, a replicação lógica decodifica transações do Write-Ahead Log em streams estruturados. Para assegurar entrega sem perdas após reinicializações, partições de rede ou falhas em consumidores, o PostgreSQL impede que qualquer arquivo de WAL contendo alterações não confirmadas—medidas a partir do restart_lsn do slot—seja reciclado pelo processo de checkpoint.
Quando uma ferramenta de CDC como o Debezium sofre com backpressure downstream, rebalanceamento de grupos de consumidores no Kafka ou erros de desserialização, ela para de enviar confirmações de LSN ao Postgres. Enquanto isso, as transações OLTP normais continuam gerando grandes volumes de escrita. O banco de dados primário retém fielmente cada segmento de WAL de 16MB gerado desde o restart_lsn. Sem limites explícitos, um consumidor travado transforma uma ferramenta de replicação resiliente em uma ameaça direta à disponibilidade de armazenamento. Equipes que operam pipelines como nossa infraestrutura kafka-debezium-dbt precisam desacoplar a ingestão da segurança do disco primário.
A interação entre o checkpointer e os replication slots esclarece a falha:
- Commit da Transação: Transações de usuários escrevem mutações no buffer de WAL, que são gravadas no arquivo ativo em
pg_wal. - Execução de Checkpoint: O checkpointer calcula o menor LSN entre todas as entradas em
pg_replication_slots. Se orestart_lsnfor anterior ao alvo do checkpoint atual, os arquivos de WAL correspondentes permanecem no disco. - Conflito com Arquivamento Contínuo: Mesmo que ferramentas como pgBackRest ou WAL-G salvem cópias remotas no S3, o PostgreSQL não pode desvincular ou apagar os arquivos locais enquanto o replication slot não avançar.
- Saturação de Disco: Ao alcançar 100% de ocupação, o PostgreSQL entra em modo de recuperação imediata para proteger a integridade dos dados, encerrando conexões ativas e interrompendo todas as operações de escrita da empresa.
Configurando Limites Rígidos com max_slot_wal_keep_size
A partir da versão 13, o PostgreSQL introduziu o parâmetro max_slot_wal_keep_size, estabelecendo um teto explícito para a quantidade de WAL retida por replication slots. Historicamente, equipes de infraestrutura dependiam de scripts em cron para inspecionar pg_replication_slots e remover consumidores travados antes do esgotamento do volume. O novo parâmetro converte uma indisponibilidade catastrófica de banco de dados em uma falha controlada de replicação.
Quando um slot acumula um atraso superior a max_slot_wal_keep_size, o PostgreSQL invalida o slot, define seu status (wal_status) como 'lost' e autoriza o checkpointer a reciclar os arquivos antigos. A base de dados preserva a disponibilidade de escrita das cargas transacionais, priorizando a estabilidade do negócio. O consumidor desconectado recebe um erro fatal ao tentar reconectar (WAL segment has already been removed) e deve executar uma nova carga inicial ou resincronização controlada.
Ajustar max_slot_wal_keep_size exige equilibrar o tempo médio de reparo (MTTR) e a capacidade livre do disco. Se a geração diária em pico for de 40 GB/hora e o storage possuir 300 GB livres antes do limite de alarme, configurar max_slot_wal_keep_size = 200GB assegura 5 horas de tolerância para falhas no CDC, mantendo 100 GB de folga para variações imprevistas.
-- Inspecionar o status dos slots de replicação e distância para os limites de disco
SELECT
slot_name,
plugin,
active,
wal_status,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS bytes_retidos,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), confirmed_flush_lsn)) AS bytes_nao_confirmados
FROM pg_replication_slots;
-- Configurar limite máximo de 150GB para retenção por slots de replicação
ALTER SYSTEM SET max_slot_wal_keep_size = '150GB';
SELECT pg_reload_conf();
Como abordado em nosso artigo sobre otimização de memória no Debezium para pipelines CDC de alto volume, o controle de backpressure deve ser ponta a ponta. Limitar memória de contêineres sem definir max_slot_wal_keep_size apenas transfere a falha do pod para o subsistema de armazenamento da base de dados.
Telemetria e Métricas de Alerta Antecipado
Aguardar alarmes de capacidade de disco do servidor (como uso acima de 85%) é um erro grave de governança operacional. No momento em que alertas de capacidade disparam durante picos de escrita, os engenheiros podem dispor de menos de 15 minutos para diagnosticar o consumidor antes do colapso do sistema. Plataformas analíticas modernas devem tratar métricas de lag de LSN como indicadores críticos em sua data-observability-platform.
Duas métricas são indispensáveis:
- Lag em Bytes: Calculado por
pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn). Indica com precisão o volume em disco retido exclusivamente pelo slot. - Deriva Temporal: Calculada pela diferença entre a hora atual (
NOW()) e a transação mais recente consumida. Revela travamentos em pipelines mesmo em horários de baixa escrita.
Recomenda-se uma matriz de escalonamento em camadas:
- Aviso (50 GB ou 25% de max_slot_wal_keep_size): Notificação para o plantonista de engenharia de dados. Verifique o lag de grupos de consumo no Kafka e integridade dos workers.
- Crítico (100 GB ou 50% de max_slot_wal_keep_size): Pausa automática de rotinas batch não essenciais para reduzir a velocidade de emissão de WAL.
- Limite de Intervenção (80% de max_slot_wal_keep_size): Script automatizado remove ou desconecta o slot secundário para salvaguardar a estabilidade do banco de dados principal.
-- Query para coletores de telemetria (Prometheus, Datadog Agent ou Grafana Agent)
SELECT
slot_name,
slot_type,
active,
wal_status,
COALESCE(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn), 0) AS slot_bytes_lag,
CASE
WHEN wal_status = 'extended' THEN 1
WHEN wal_status = 'unreserved' THEN 2
WHEN wal_status = 'lost' THEN 3
ELSE 0
END AS wal_status_code
FROM pg_replication_slots;
Procedimentos de Recuperação Após Invalidação de Slot
Quando um replication slot atinge o estado 'lost', os consumidores sofrem erros imediatos de desconexão. Recuperar o pipeline exige decisões claras entre tempo de entrega, custos computacionais e consistência transacional. Apenas recriar o slot e reativar a leitura gera lacunas definitivas de dados, correspondentes aos arquivos de WAL já deletados.
Procedimento 1: Descarte e Recriação do Slot Comprometido
O slot invalidado precisa ser formalmente removido para liberar referências internas no catálogo do PostgreSQL:
-- Excluir slot invalidado com segurança
SELECT pg_drop_replication_slot('debezium_orders_cdc');
-- Recriar slot lógico limpo usando o plugin pgoutput ou test_decoding
SELECT pg_create_logical_replication_slot('debezium_orders_cdc', 'pgoutput');
Procedimento 2: Snapshot Ad-Hoc Incremental Sem Interrupção Global
Reiniciar toda a captura histórica em tabelas com múltiplos terabytes para corrigir um slot falho causa atrasos inaceitáveis nos painéis corporativos. Plataformas avançadas utilizam snapshots incrementais orientados por sinais. Ao registrar um comando em uma tabela de sinalização, o Debezium executa a leitura das tabelas afetadas em paralelo com o streaming ativo, sem exigir o reprocessamento de todo o data lakehouse.
-- Inserir comando de snapshot ad-hoc na tabela de sinais do Debezium
INSERT INTO debezium_signal (id, type, data)
VALUES (
'ad-hoc-snapshot-recovery-001',
'execute-snapshot',
'{"data-collections": ["public.orders", "public.order_line_items"], "type": "INCREMENTAL"}'
);
Essa abordagem permite que as operações de escrita continuem sendo entregues via novo replication slot enquanto a lacuna histórica é corrigida em segundo plano, mantendo a consistência dos dados downstream.
Padrões de Arquitetura para Isolar o CDC do Banco Primário
Líderes de engenharia e arquitetos de dados devem mitigar o acoplamento direto entre consumidores analíticos e bancos de dados OLTP de produção. Transtornos no pipeline analítico jamais devem derrubar os sistemas transacionais da empresa. Dois padrões reduzem sensivelmente essa vulnerabilidade:
Padrão A: Execução de CDC em Réplicas de Leitura Físicas
A partir do PostgreSQL 16, replication slots lógicos podem ser configurados em réplicas de leitura físicas com suporte a failover ordenado. Com a diretiva standby_slot_names ativa na instância primária, o Postgres garante a replicação do WAL para a réplica antes do descarte, enquanto o consumidor Debezium consome exclusivamente do nó standby. Se o slot atrasar, o impacto em disco fica restrito à réplica, blindando o nó mestre.
Padrão B: Padrão do Encaminhador em Buffer Leve
Em vez de carregar transformações pesadas, formatação de tipos ou validações de esquema diretamente dentro da engine de decodificação lógica do Postgres, implemente um consumidor mínimo cujo único papel seja persistir o payload binário em um buffer resiliente (como tópicos do Apache Kafka ou filas seguras). Um consumidor simplificado raramente sofre com pausas longas ou falhas de memória, diminuindo os riscos de retenção de WAL. Etapas de modelagem e transformação são delegadas integralmente às camadas downstream.
Checklist Operacional de Resiliência de WAL
Antes de liberar replication slots lógicos em ambientes de produção, certifique-se de que cada salvaguarda esteja plenamente validada:
- Definir
max_slot_wal_keep_sizeem todos os nós primários alinhado à capacidade física dos discos. - Implementar telemetria de
pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)com alarmes em 25% e 50% da margem útil. - Assegurar provisionamento de disco elástico ou alertas automatizados de infraestrutura na nuvem.
- Documentar e automatizar o descarte emergencial de slots que ultrapassem 80% do limite tolerável.
- Validar rotinas de snapshot incremental ad-hoc em ambiente de homologação para recuperação célere de slots invalidados.