Pular para o conteudo principal

O cache não é o band-aid mágico para banco lento

Como pensar em cache como cópia com custo de consistência, e não como desculpa automática para esconder query ruim, modelagem ruim ou leitura mal desenhada.

Andrews Ribeiro

Andrews Ribeiro

Founder & Engineer

Trilha

Trilha de system design para entrevistas

Etapa 5 / 19

O problema

Cache costuma entrar na conversa como reflexo.

A leitura ficou lenta?

  • coloca cache

O endpoint está sofrendo?

  • coloca cache

O banco está caro?

  • coloca cache

Isso parece pragmático.

Mas muitas vezes é só uma forma elegante de empurrar o problema para outro lugar.

Porque a pergunta real não é:

  • “dá para colocar cache?”

A pergunta real é:

  • “estou acelerando a leitura certa ou escondendo um desenho ruim?”

Se a consulta está ruim, o índice está faltando, o ORM está disparando N+1 ou a tela pede dado demais, cache pode melhorar benchmark e piorar entendimento do sistema.

E pior:

pode melhorar benchmark enquanto entrega dado velho para o usuário.

Modelo mental

Pense assim:

cache é uma cópia temporária da verdade feita para evitar buscar o dado original toda vez.

Essa frase já resolve metade da confusão.

Se cache é cópia, então a conversa muda.

Você precisa responder:

  • quão velha essa cópia pode ficar
  • quem atualiza essa cópia
  • quando ela deixa de ser confiável
  • o que acontece se o usuário enxergar esse atraso

Ou seja:

cache não é só performance.

É performance comprada com risco de consistência.

Quebrando o problema

Cache bom acelera leitura repetida e cara

Cache costuma fazer muito sentido quando existe um padrão assim:

  • mesma leitura acontece o tempo todo
  • buscar a origem é caro
  • um pequeno atraso é aceitável
  • a política de atualização é compreensível

Exemplos comuns:

  • página de produto com conteúdo estável
  • configuração pública
  • ranking que pode atrasar um pouco
  • lista muito lida e pouco alterada

Nesses casos, a cópia temporária costuma pagar bem.

Cache ruim vira maquiagem para causa mal entendida

Esse é o tropeço mais comum.

A leitura está ruim, mas a causa pode ser:

  • query torta
  • índice faltando
  • N+1
  • join exagerado
  • select * desnecessário
  • tela pedindo coisa demais

Se você joga cache em cima sem entender isso, corre o risco de:

  • preservar a causa
  • aumentar complexidade
  • dificultar debug
  • criar dado desatualizado

Então maturidade aqui começa com uma pergunta simples:

  • “por que essa leitura está cara hoje?”

TTL não é estratégia completa

Muita gente acha que resolveu cache quando definiu:

  • TTL = 5 minutos

Só que TTL sozinho é só uma das peças.

Ele responde:

  • por quanto tempo a cópia pode existir sem ser forçada a expirar

Mas não responde tudo.

Você ainda precisa pensar:

  • e se o dado mudar antes?
  • e se a cópia vencer ao mesmo tempo para muita gente?
  • e se essa leitura não puder esperar tanto?

TTL ajuda.

Mas não substitui raciocínio de invalidação.

Dado diferente pede tolerância diferente

Esse ponto costuma ser ignorado cedo demais.

Algum atraso pequeno pode ser aceitável para:

  • descrição de produto
  • avatar
  • ranking
  • contagem de likes

O mesmo atraso pode ser péssimo para:

  • saldo
  • estoque apertado
  • permissão
  • estado de pagamento

Se você usa a mesma estratégia para tudo, o cache deixa de ser otimização e vira mentira bem embalada.

Invalidação é decisão de produto também

Outro erro frequente é tratar invalidação como detalhe de infra.

Não é só isso.

A pergunta “quando este cache deve morrer?” costuma depender de:

  • impacto no usuário
  • risco do dado velho
  • fluxo de atualização
  • frequência de leitura

Por isso, invalidação boa não nasce só de ferramenta.

Nasce de entender que verdade o usuário espera ver naquela tela ou naquele fluxo.

Cache na camada errada também dói

Às vezes o problema não é usar cache.

É usar na camada errada.

Você pode cachear:

  • consulta no banco
  • resposta da API
  • fragmento da página
  • objeto na aplicação
  • edge/CDN

Cada camada tem custo e benefício diferente.

Cachear a página inteira quando só o preço muda muito talvez seja pior do que cachear só a parte estável.

Cachear resultado por usuário quando quase tudo é compartilhado talvez desperdice memória.

Ou seja:

além de decidir se vai usar cache, você precisa decidir onde.

Cache miss e stampede também entram na conta

Outro ponto que separa resposta madura de resposta decorada:

cache não é só hit bonito.

Também existe:

  • miss caro
  • expiração simultânea
  • rajada de recomputação

Se muita requisição perde a cópia ao mesmo tempo, você pode devolver a pressão inteira para a origem justo no pior momento.

Então performance com cache também precisa olhar comportamento quando o cache falha.

Exemplo simples

Imagine uma página de produto com:

  • nome
  • descrição
  • imagem
  • preço
  • estoque

A reação preguiçosa seria:

  • cachear tudo por 10 minutos

Parece ótimo até começar promoção ou estoque apertado.

Agora o usuário vê:

  • preço antigo
  • estoque antigo

E o sistema real já não consegue honrar aquilo.

Uma decisão mais saudável talvez seja:

  • cachear descrição e imagem por mais tempo
  • tratar preço com TTL menor ou leitura mais fresca
  • invalidar cópia quando mudança relevante de estoque acontecer

O ponto não é “usar cache ou não”.

É decidir qual parte do dado pode ser cópia sem trair o comportamento esperado.

Erros comuns

  • Adicionar cache antes de provar o gargalo.
  • Usar cache para esconder N+1, query ruim ou modelagem ruim.
  • Tratar TTL como solução completa.
  • Assumir que todo dado suporta atraso.
  • Ignorar o comportamento quando o cache expira ou falha.
  • Medir só latência média e esquecer erro percebido pelo usuário.

Como um senior pensa

Um senior raramente abre a conversa com:

  • “vamos subir um Redis”

Ele costuma começar com algo mais útil:

  • “qual leitura está cara?”
  • “por que ela está cara?”
  • “quanto de atraso o negócio tolera?”
  • “o que acontece se o usuário enxergar dado velho?”

Essa ordem melhora tudo.

Porque às vezes a resposta certa é:

  • arrumar query
  • criar índice
  • cortar payload
  • mudar modelagem

E só depois falar de cache.

Quando cache faz sentido, ele também tenta mantê-lo honesto:

  • define frescor aceitável
  • pensa em invalidação
  • escolhe a camada certa
  • olha miss e recomputação

Ele não usa cache para ganhar gráfico.

Usa para reduzir custo sem quebrar confiança.

O que o entrevistador quer ver

Em entrevista, cache separa bem resposta decorada de resposta madura.

O avaliador costuma querer ver se você:

  • entende cache como cópia
  • fala de consistência junto com latência
  • diferencia tipos de dado
  • não vende cache como primeira resposta para tudo

Uma resposta forte costuma ter esta forma:

“Eu só colocaria cache depois de entender por que a leitura está cara. Se o problema for query ruim ou N+1, eu prefiro corrigir a causa primeiro. Quando cache faz sentido, trato como cópia temporária da verdade: defino quão velho o dado pode ficar, escolho a camada certa e penso em invalidação e comportamento em caso de miss. Nem todo dado aceita o mesmo atraso.”

Isso mostra critério.

Muito mais do que falar “coloca Redis” em 10 segundos.

Cache acelera leitura. Não apaga a obrigação de dizer quão longe da verdade você aceita ficar.

Se a causa é query ruim, cache pode virar só um curativo bonito em cima de um sistema ainda doente.

Resumo rápido

O que vale manter na cabeça

Checklist de pratica

Use isto ao responder

Você concluiu este artigo

Parte da trilha: Trilha de system design para entrevistas (5/19)

Próximo artigo Índices: quando ajudam e quando atrapalham Artigo anterior Race condition na prática

Continue explorando

Artigos relacionados