Pular para o conteudo principal

Consistência de cache interno sem invalidar no desespero

Quando o cache interno fica inconsistente e o time responde com invalidação em massa, o backend troca previsibilidade por pânico operacional.

Andrews Ribeiro

Andrews Ribeiro

Founder & Engineer

O problema

Cache interno costuma começar simples.

Depois aparecem sintomas:

  • dado velho demais
  • resultado divergente
  • invalidação que chega tarde
  • rebuild caro demais

Nesse ponto, muita equipe entra em modo reflexo:

  • apaga tudo
  • reduz TTL no chute
  • inválida em cascata
  • adiciona mais um if na escrita

Isso não é estratégia.

É susto operacional.

Modelo mental

Cache interno precisa responder três perguntas:

  • qual dado pode envelhecer?
  • por quanto tempo?
  • quem tem autoridade para dizer que aquilo mudou?

Sem isso, a discussão fica presa em:

  • “esse cache está inconsistente”

Mas inconsistente em relação a quê?

À origem transacional? Ao evento mais recente? Ao que a interface esperava naquele segundo?

Cache bom não é o que nunca diverge.

É o que diverge de forma conhecida e aceitável.

Exemplo simples

Imagine um read model de saldo usado em dashboard operacional.

A origem real é atualizada em fluxo transacional.

O dashboard aceita alguns segundos de atraso.

Se você tratar qualquer diferença como bug crítico, vai empurrar o sistema para:

  • invalidação a cada mutação
  • recomputação demais
  • dependência temporal entre escrita e leitura

Se o contrato disser claramente “até 30 segundos de atraso é aceitável”, a arquitetura fica muito mais honesta.

O erro comum

O erro comum é usar a mesma política para tudo.

Por exemplo:

  • TTL curto para qualquer caso
  • invalidação global sempre que algo muda
  • rebuild completo porque um item mudou

Outro erro comum é achar que evento de invalidação resolve tudo sozinho.

Evento também atrasa. Também perde ordem. Também pode falhar.

Se a arquitetura depende de invalidação perfeita para não mentir, ela já está frágil.

O que normalmente ajuda

Normalmente ajuda separar quatro coisas:

  • cache que só acelera leitura repetida
  • cache que sustenta read model
  • cache que pode cair sem impacto funcional
  • cache que precisa de política de reconciliação

Na prática, isso costuma levar a:

  • TTL explícito quando atraso é aceitável
  • invalidação por chave quando a mudança é localizada
  • rebuild sob demanda quando o custo compensa
  • reconciliação operacional para corrigir drift sem travar o fluxo normal

Não é sobre escolher uma técnica universal.

É sobre parar de tratar todo drift como incêndio.

Como um senior pensa

Quem já sofreu com invalidação no desespero costuma perguntar:

  • esse cache tem contrato de frescor ou só esperança?
  • o sistema sabe operar com dado levemente velho?
  • quem decide que esse valor ficou obsoleto?
  • estou invalidando porque o modelo é bom ou porque não confio nele?

Essa conversa normalmente reduz muito a vontade de sair apagando tudo.

Ângulo de entrevista

Esse tema aparece em backend, system design, performance e consistência.

O entrevistador quer ver se você entende:

  • que cache interno é decisão de semântica, não só de velocidade
  • que staleness aceitável precisa ser explícita
  • que invalidação em massa costuma denunciar fronteira ruim

Resposta forte costuma soar assim:

“Eu não trataria qualquer divergência de cache como motivo para invalidar tudo. Primeiro definiria quais leituras toleram atraso, qual origem manda e qual política faz sentido por tipo de dado. Sem isso, a invalidação vira só reação de pânico.”

Takeaway direto

Cache inconsistente não se corrige no desespero.

Se corrige com contrato melhor.

Resumo rápido

O que vale manter na cabeça

Checklist de pratica

Use isto ao responder

Você concluiu este artigo

Próximo artigo Contrato interno entre módulos sem inventar RPC dentro do mesmo app Artigo anterior Circuit breaker interno entre módulos

Continue explorando

Artigos relacionados