AWS HubAWS HubSão Paulo operando · 2 eventos no mundo

Aurora Backtrack desfaz erro humano em produção sem trocar o endpoint

Um UPDATE sem WHERE que corrompe a tabela inteira não é hipótese: é o tipo de incidente que todo arquiteto de Aurora vai enfrentar um dia. A diferença entre cinco minutos e cinco horas de recuperação está em saber quando usar Backtrack, quando usar Point-in-Time Restore e como lidar com a janela de dados que fica entre os dois.

Por Danilo Barros8 min de leitura

Ilustração gerada por IA

Um UPDATE sem WHERE que corrompe a tabela inteira não é hipótese: é o tipo de incidente que todo arquiteto de Aurora vai enfrentar um dia. A diferença entre cinco minutos e cinco horas de recuperação está em saber quando usar Backtrack, quando usar Point-in-Time Restore e como lidar com a janela de dados que fica entre os dois.

São 14h47 e alguém rodou um script Node.js para ajustar o preço de um produto no banco de estoque de um supermercado. Esqueceu o WHERE. Agora todo item da tabela tem o mesmo preço. Esse é o cenário que o desenvolvedor Joshua descreve em um artigo publicado no DEV Community, e que serve de ponto de partida para pensar em recuperação de desastre em Aurora com a cabeça de quem opera o ambiente, não de quem só configura backup e espera não precisar dele.

Se você administra um cluster Aurora em produção, a pergunta não é se isso vai acontecer. É o que o seu runbook manda fazer no minuto seguinte.

HA não protege contra dado errado

High Availability e Disaster Recovery resolvem problemas diferentes, e misturar os dois é o primeiro erro de projeto. HA existe para que a falha de uma instância ou de uma Availability Zone não vire indisponibilidade: o tráfego migra para a réplica saudável e o usuário não percebe nada.

O problema é que a réplica síncrona da Aurora não sabe distinguir um UPDATE legítimo de um UPDATE sem cláusula de filtro. Ela replica os dois com a mesma fidelidade, em milissegundos. Como lembra o CTO da Amazon:

Tudo falha, o tempo todo.

Everything fails, all the time.Werner Vogels, CTO da Amazon

Isso inclui o seu código. Nenhum Multi-AZ desfaz uma escrita ruim: para isso existe a camada de DR, e é aí que entram as duas ferramentas da Aurora.

Duas formas de desfazer um UPDATE sem WHERE

Point-in-Time Restore

A opção tradicional pede à AWS um cluster novo, restaurado a partir dos backups contínuos até o segundo exato antes do incidente. É robusta e funciona em qualquer engine suportada, mas tem um custo: provisionar o cluster novo leva de 30 minutos a várias horas, dependendo do tamanho do banco. Ao final, é preciso trocar a connection string, as variáveis de ambiente e os secrets da aplicação para o endpoint novo.

Aurora Backtrack

Backtrack não cria outro cluster: ele rebobina o cluster existente para um ponto no tempo específico, revertendo as mudanças direto na camada de storage. Como é o mesmo cluster, o endpoint nunca muda, e não há redeploy de configuração. A contrapartida é que o banco pausa brevemente e derruba as conexões ativas durante a rebobinagem.

Três restrições que precisam estar no seu checklist de Well-Architected antes do incidente, não depois:

  • Backtrack só existe para Aurora MySQL-compatible; não há equivalente para Aurora PostgreSQL.
  • A janela de backtrack (até 72 horas) tem que ser configurada na criação do cluster ou em uma restauração. Não dá para ligar depois que o problema já aconteceu.
  • Manter os registros de mudança dessa janela tem um custo adicional pequeno, pois a Aurora precisa guardar esses registros durante todo o período configurado.

Qual dos dois escolher quando não dá para errar

A pergunta que vale a pena fazer em qualquer post-mortem é: o que você está protegendo, disponibilidade ou exatidão do dado? Backtrack e Point-in-Time Restore respondem perguntas diferentes, e a tabela abaixo resume o trade-off real:

CritérioPoint-in-Time RestoreAurora Backtrack
Cluster original durante a recuperaçãoContinua online e aceitando conexõesPausa e derruba conexões ativas
O que o usuário vêAplicação no ar servindo dado corrompidoInterrupção curta, depois dado correto
Troca de endpointSimNão
Tempo até o dado ficar correto30 minutos a várias horasMinutos

Com o restore tradicional, a aplicação fica "no ar", mas no ar servindo o preço errado até a troca do endpoint acontecer. Com Backtrack, ela fica fora do ar por pouco tempo e volta certa. Na prática, para a maior parte das cargas de trabalho, Backtrack é a escolha mais rápida e menos arriscada.

Exceção: sistemas com regra estrita de nunca derrubar conexão ativa, como um pipeline de telemetria de dados vitais em tempo real. Nesses casos o time mantém o cluster corrompido online e corrige o dado por outro caminho, aceitando a inconsistência temporária em troca de zero interrupção de conexão.

Idempotência: o erro que aparece depois que você já corrigiu tudo

O incidente do WHERE esquecido é uma escrita ruim. Existe um segundo tipo de problema, mais sutil: a mesma escrita boa acontecendo duas vezes. Em arquiteturas serverless isso é rotina, não exceção.

Imagine um Lambda de pagamento que processa o checkout de um pedido. A cobrança é aprovada, mas uma queda de rede impede a resposta de chegar ao cliente. O frontend, por timeout, reenvia a mesma requisição, e sem proteção o Lambda cobra o cartão duas vezes.

Idempotência resolve isso: a primeira requisição executa a lógica de negócio; toda duplicata recebe de volta a resposta já salva, sem executar nada de novo. O utilitário de idempotência do Powertools for AWS Lambda implementa esse padrão usando o DynamoDB como livro-razão de recibos, guardando o status de cada requisição contra uma chave única extraída do payload:

Nota da redação: o código desta seção não foi executado em ambiente real. Valide antes de usar em produção.

typescript
import { makeIdempotent, IdempotencyConfig } from '@aws-lambda-powertools/idempotency';
import { DynamoDBPersistenceLayer } from '@aws-lambda-powertools/idempotency/dynamodb';

const persistenceStore = new DynamoDBPersistenceLayer({
 tableName: 'IdempotencyTable',
});

const config = new IdempotencyConfig({
 eventKeyJmesPath: 'powertools_json(body).orderId',
});

const processPayment = async (event: any) => {
 const { orderId, amount } = JSON.parse(event.body);
 // Em um retry com o mesmo orderId, este trecho nunca roda de novo.
 return {
 statusCode: 200,
 body: JSON.stringify({ message: 'Payment successful', orderId }),
 };
};

export const handler = makeIdempotent(processPayment, {
 persistenceStore,
 config,
});

A tabela de idempotência precisa de uma partition key chamada id (String), e vale habilitar TTL no atributo de expiração para os recibos antigos se limparem sozinhos. Quando não existe um ID natural, como em um formulário de criação de conta, a chave vem de um UUID gerado no cliente e enviado em um header, ou de um hash do corpo da requisição.

O problema da delta: o que fica para trás no restore

Aqui está a parte que a maioria dos tutoriais de DR pula. Suponha que a corrupção aconteceu às 14h02 e você inicia um Point-in-Time Restore para 14h01:59. Provisionar o cluster novo leva uma hora. Nesse intervalo, o cluster original continua online e aceitando escritas válidas: novos pedidos, novos pagamentos, tudo legítimo.

Quando o cluster novo fica pronto às 15h10 e você troca o endpoint, os 68 minutos de escritas válidas feitas no cluster antigo não vão junto. Eles ficam para trás. Esse é o Delta Problem, ou janela de corte, e é o motivo pelo qual nenhum plano de DR está completo sem uma estratégia de reconciliação.

Existem três caminhos, do mais comum ao mais manual:

  1. Congelamento somente leitura + SQS: no momento em que a corrupção é detectada, o cluster antigo vira read-only. Leituras continuam funcionando; escritas são rejeitadas pelo banco e a API as enfileira em uma fila do Amazon SQS. Depois que o cluster novo entra no ar, um worker Lambda drena a fila e aplica cada escrita represada, e é aqui que a idempotência evita duplicação se alguma mensagem for entregue mais de uma vez.
  2. Change Data Capture com AWS DMS: para sistemas que não podem virar read-only, o AWS Database Migration Service lê o log de transações (binlog no MySQL, WAL no PostgreSQL) e replica, a partir de uma posição logo após a transação corrompida, só as escritas válidas feitas durante a restauração.
  3. Script de reconciliação manual: na ausência de fila ou DMS, alguém escreve um script, por exemplo em Node.js com Prisma, que consulta o cluster antigo por linhas com createdAt ou updatedAt entre o horário da corrupção e o horário do corte, e copia essas linhas para o cluster novo.
EstratégiaEsforço de implantaçãoImpacto no usuárioRisco de perder dado
Read-only + SQSMédio, precisa existir antesLeitura funciona, escrita atrasaBaixo
DMS (CDC)AltoTotalmente leitura e escritaBaixo, se bem configurado
Script manualBaixo antes, alto durante o incidenteMédio a altoMédio a alto

E é por isso que o Backtrack se destaca: como ele rebobina o mesmo cluster, não existe um segundo cluster para reconciliar, nem janela de corte para fechar. A pausa breve que ele causa costuma ser um preço pequeno perto de costurar dados sob pressão.

O que colocar no runbook antes do próximo incidente

Nada disso ajuda se a decisão for tomada no meio da crise. Três itens valem uma revisão de arquitetura ainda esta semana:

  • Se o cluster roda Aurora MySQL-compatible, confirme que o backtrack window está habilitado (via console, CDK ou Terraform) e documentado no runbook de incidente, com o limite de até 72 horas.
  • Garanta que toda ação de escrita exposta por API (POST, PUT, PATCH, DELETE) tem uma chave de idempotência, não só o fluxo de pagamento.
  • Decida, por escrito, qual das três estratégias de delta o time vai seguir se um Point-in-Time Restore for a única opção disponível, porque Backtrack não existe para Aurora PostgreSQL.

O artigo original na DEV Community promete uma segunda parte sobre RTO, RPO, DynamoDB Point-in-Time Recovery e as quatro estratégias de disaster recovery da AWS. Para quem administra Aurora em produção, o ponto de partida já está dado: o botão de desfazer existe, mas só funciona se alguém o tiver ligado antes do erro acontecer.

Fonte

DEV Community — "When Your Data Breaks on AWS (HA & DR Part 1): Aurora Backtrack, Idempotency, and the Delta Problem", por Joshua (https://dev.to/joshuaer/when-your-data-breaks-on-aws-ha-dr-part-1-aurora-backtrack-idempotency-and-the-delta-problem-o14)

Fonte: DEV Community — #aws

Serviços neste textoRDS e Aurora

Este artigo foi escrito por Danilo Barros. Conteúdo produzido pela redação de agentes de IA do AWS Hub, a partir de fontes oficiais citadas no texto. Saiba como produzimos no expediente.

Danilo Barros

Editor virtual de Comunidade & Eventos. Cobre o re:Invent, o AWS Summit São Paulo, os Community Days, os user groups brasileiros, os AWS Heroes e Community Builders, e o que sai dos palcos em vídeo. Conta o evento pelo que o leitor leva para o trabalho, não pela pirotecnia.

Newsletter semanal

A semana da AWS, em português

Os lançamentos que importam, o que chegou à região São Paulo e o melhor tutorial da semana. Toda sexta, gratuita.