CEVIU Logo
Voltar
Failover inseguro no PostgreSQL no Kubernetes: lição prática de alta disponibilidade

Failover inseguro no PostgreSQL no Kubernetes: lição prática de alta disponibilidade da Datadog

Aprofundamento CEVIU

Aprofundamento

A Datadog não descobriu um bug no Patroni ou no PostgreSQL, descobriu uma contradição estrutural entre o modelo de alta disponibilidade esperado e a realidade operacional em Kubernetes. O problema não estava na ferramenta, mas na configuração: replicação assíncrona + maximum_lag_on_failover rígido + rede instável = failover bloqueado por segurança. Isso expôs uma armadilha comum em ambientes de nuvem: assumir que 'zona de falha' é só um data center físico, quando na verdade pode ser uma partição de rede entre pods no mesmo cluster, causada por políticas de CNI, limites de QoS ou até por uma atualização de kernel no nó.

O ajuste para synchronous_commit = remote_apply não é só sobre durabilidade, é uma mudança de contrato operacional. Agora, cada escrita depende da aplicação física do WAL em outro nó, não só do recebimento. Isso exige monitoramento de três métricas críticas em tempo real: pg_stat_replication.sync_state (para confirmar se o standby está realmente em 'sync'), pg_wal_lsn_diff entre primary e standby, e o tempo de resposta do ZooKeeper ao tentar adquirir o lock de líder. Sem isso, você troca perda de dados por latência cega.

O que mudou

Em abril, a CEVIU já havia reportado que a Datadog migrava cargas pesadas de Postgres para outros stacks, como na otimização da página de métricas (06/04). Mas ali era uma questão de desempenho de consulta. Agora, em 19/06, a mudança é de política de consistência: de async replication + lag threshold para sync replication + remote_apply. Não é mais 'quanto posso tolerar de atraso?', mas 'quanto posso garantir que não haverá divergência?'. A diferença prática? Antes, um gameday com latência de rede travava o cluster. Agora, o mesmo cenário faz o leader rejeitar transações antes mesmo de elas serem confirmadas, e o failover ocorre em segundos, com RPO=0.

Por que isso importa

Isso importa porque sua equipe de SRE provavelmente ainda opera com maximum_lag_on_failover = 100MB e synchronous_commit = on, achando que está seguro. Mas 'on' não garante aplicação, só confirmação de recebimento. Em Kubernetes, onde redes são compartilhadas, esse gap entre 'recebido' e 'aplicado' é onde moram os incidentes pós-failover. Se seu backup usa pg_basebackup sem validar o LSN aplicado no standby, você pode estar restaurando um snapshot inconsistente sem saber. E se seu runbook de DR ainda pressupõe que 'uma réplica é sempre promovível', ele está obsoleto desde junho de 2026.

Linha do tempo

  1. CEVIU publica análise sobre os desafios de Day 2 na execução de bancos de dados em Kubernetes, destacando que resiliência e failover exigem expertise além do deploy inicial.

  2. Pane na AWS US-EAST-1 mostra que falhas regionais afetam diretamente a capacidade de recuperação de bancos de dados distribuídos, reforçando a necessidade de testes realistas de failover.

  3. Datadog revela falha crítica de failover inseguro em PostgreSQL no Kubernetes durante gameday, levando à adoção de replicação síncrona com remote_apply.

Perguntas frequentes

Qual é a diferença prática entre synchronous_commit = on e remote_apply?

Com 'on', o líder espera confirmação de que o standby recebeu o WAL. Com 'remote_apply', espera confirmação de que o standby *aplicou* o WAL localmente. Isso elimina o risco de promover um nó que tem os logs, mas ainda não executou as mudanças, o que geraria inconsistência imediata após o failover.

Por que usar synchronous replication só nos standbys do leader pool e não nas réplicas de leitura?

Porque réplicas de leitura não participam de failover. Impor sincronia nelas aumentaria latência desnecessariamente para cargas que só leem. O custo de durabilidade deve ser aplicado apenas onde ele impacta a recuperação, ou seja, nos nós que podem virar primários.

Como saber se meu Patroni está realmente usando remote_apply após a configuração?

Não basta olhar o patronictl edit-config. Verifique em tempo real: execute 'SELECT * FROM pg_stat_replication' no primary, a coluna 'sync_state' deve mostrar 'sync', não 'quorum' ou 'async'. Também confira 'pg_current_wal_lsn(), replay_lsn' no standby: se for maior que zero, o WAL ainda não foi aplicado, mesmo com sync_state='sync'.

O que acontece se o único standby síncrono cair durante uma transação?

O líder entra em modo 'degraded': transações passam a ser confirmadas com synchronous_commit = local (ou off, dependendo da fallback configuration). Patroni reconfigura automaticamente o synchronous_standby_names para incluir outro nó elegível, mas só se ele estiver com lag <= 10 MB e conectado ao ZooKeeper. Se nenhum estiver apto, o sistema prioriza disponibilidade, não durabilidade.

Fontes

Avalie este artigo:
Compartilhar:
Categoria
CEVIU DevOps
Publicado
19 de junho de 2026
Editoria
CEVIU DevOps

Quer receber mais sobre CEVIU DevOps?

Conteúdo curado diariamente, direto no seu e-mail.

Conteúdo curado diariamenteDiversas categoriasCancele quando quiser