DevGuideTK
← Trilha Backend

Cache

Estratégias para guardar respostas caras, e o problema difícil de saber quando descartá-las.

O que é cache

Toda vez que o sistema mostra a página de um produto, ele consulta o banco: nome, preço, fotos, avaliações. Se a página é aberta mil vezes por minuto e o produto muda uma vez por dia, o banco responde a mesma pergunta mil vezes para devolver a mesma resposta.

Um cache guarda essa resposta num lugar mais rápido e mais próximo. Na próxima vez, o sistema confere o cache primeiro:

  • Acerto (hit): a resposta está no cache e é devolvida na hora.
  • Falha (miss): a resposta não está, ou expirou. O sistema busca na origem, devolve e guarda uma cópia para as próximas.

A proporção de acertos sobre o total de leituras é a taxa de acerto. Um cache com 95% de acerto tira 95% da carga de leitura da origem. Com 30%, ele quase só acrescenta complexidade.

Por que funciona: a distância dos dados

O ganho do cache vem da diferença de velocidade entre os lugares onde um dado pode estar. As ordens de grandeza abaixo são aproximadas e variam com o hardware e a rede, mas a proporção entre elas é o que importa:

Onde está o dadoTempo típico para obtê-lo
Memória do próprio processoMenos de 1 microssegundo
Redis na mesma redeCerca de 0,2 a 1 milissegundo
Consulta simples ao banco, com índiceCerca de 1 a 5 milissegundos
Consulta pesada, com agregaçõesDezenas a centenas de milissegundos
Chamada a uma API externaDezenas a centenas de milissegundos

Quanto mais cara a origem, maior o ganho. Guardar em cache uma consulta de 2 milissegundos no Redis economiza pouco. Guardar um relatório que leva 800 milissegundos economiza muito.

Onde os caches ficam

Um pedido passa por várias camadas, e cada uma pode guardar uma cópia:

CamadaExemploO que guarda
NavegadorCache HTTP do navegadorImagens, scripts, respostas com Cache-Control
CDNServidores perto do usuárioArquivos estáticos e respostas públicas
Aplicação, em memóriaUm mapa ou uma biblioteca de cache no processoDados muito lidos, por pouco tempo
Cache distribuídoRedis, MemcachedDados compartilhados por todas as instâncias da aplicação
Banco de dadosPáginas de dados mantidas em memóriaAs tabelas e índices mais acessados

Este tópico trata das duas camadas do meio, que ficam sob controle direto do código do backend. O cache HTTP e a CDN têm seus próprios tópicos.

O problema difícil: quando a cópia deixa de valer

Guardar uma cópia é fácil. O difícil é que, a partir desse momento, existem duas versões do dado: a da origem e a do cache. Quando a origem muda, o cache continua entregando a versão antiga até que alguém a descarte. Esse descarte se chama invalidação.

Há duas formas básicas de invalidar:

  • Por tempo: cada item tem um tempo de vida (TTL). Depois dele, o item expira e a próxima leitura busca na origem. É simples e sempre funciona, mas o dado pode ficar velho durante todo o TTL.
  • Por evento: quando o dado muda, o código que fez a mudança apaga ou atualiza a cópia. O dado fica atualizado quase na hora, mas todo caminho que altera o dado precisa lembrar de invalidar.

Na prática, usa-se as duas juntas. A invalidação por evento mantém o cache atualizado, e o TTL limita o estrago quando algum caminho esquece de invalidar.

O que vale a pena guardar

Um dado é um bom candidato a cache quando reúne quatro características:

CaracterísticaPor quê
É lido com frequênciaSem leituras repetidas, a taxa de acerto fica baixa
É caro de obterSe a origem já é rápida, o ganho é pequeno
Muda poucoDados que mudam a todo segundo vivem expirando ou ficando velhos
Aceita ficar um pouco velhoUm preço com um minuto de atraso pode ser aceitável; um saldo bancário, não

O catálogo de produtos, configurações, permissões de um perfil, resultados de busca populares e respostas de APIs externas costumam se encaixar. Saldos, estoque no momento da compra e qualquer dado usado para decidir uma transação, em geral, não.

Por que isso importa quando a IA escreve o código

Pedir "coloque cache nesta função" gera código que funciona no primeiro teste. Os problemas aparecem com o tempo e com carga:

  • O item é guardado sem TTL, e um dado errado fica para sempre.
  • A alteração do dado não invalida o cache, e a tela mostra o valor antigo até alguém reiniciar o Redis.
  • A chave não inclui o usuário, e um cliente vê o carrinho de outro.
  • Uma chave popular expira e centenas de requisições vão ao banco ao mesmo tempo.
  • O cache vira a única cópia de um dado, e uma reinicialização do Redis o apaga.

O próximo nível compara as estratégias de cache e as formas de evitar esses problemas.

Prompts para aprofundar

Ao abrir no ChatGPT ou no Claude, o prompt é enviado ao serviço escolhido pela URL e também fica copiado na sua área de transferência.

  • Cache em cinco minutos

    Explique em no máximo cinco minutos de leitura o que é cache no backend, para alguém que programa mas nunca colocou um cache em produção.
    
    Cubra só o essencial: o que é acerto e falha, por que o cache acelera, o que é invalidação e por que ela é a parte difícil, e que tipo de dado vale a pena guardar.
    
    Use o exemplo da página de um produto numa loja virtual. No final, me faça três perguntas curtas para eu verificar se entendi, e corrija as minhas respostas.
  • Do pedido ao dado, camada por camada

    Quero entender onde os caches ficam no caminho de um pedido e o que cada um guarda.
    
    Aja como um mentor de backend. Pergunte primeiro qual é a minha experiência e qual é a arquitetura do sistema em que eu trabalho.
    
    Acompanhe um pedido para a página de um produto, desde o navegador até o banco, e explique, camada por camada:
    1. O cache do navegador e o papel do cabeçalho Cache-Control.
    2. A CDN.
    3. O cache em memória da aplicação.
    4. O cache distribuído, como o Redis.
    5. O cache interno do banco de dados.
    
    Para cada camada, diga o que ela guarda, quem a controla, como ela é invalidada e qual é o tempo típico de resposta. Faça uma pergunta de verificação ao fim de cada camada e só avance depois da minha resposta.
  • Por que invalidar cache é difícil

    Quero entender por que se diz que invalidar cache é um dos problemas difíceis da computação.
    
    Explique a invalidação por tempo e por evento, e depois me apresente estes cenários, um de cada vez, perguntando o que acontece e por quê:
    1. O preço de um produto muda, e o código apaga o cache antes de confirmar a transação no banco.
    2. Duas alterações simultâneas do mesmo produto gravam o novo valor no cache, em vez de apagar.
    3. Três instâncias da aplicação têm cache em memória, e só uma recebe a alteração.
    4. Um item foi guardado sem TTL, e um dos caminhos de alteração esqueceu de invalidar.
    5. Um script de correção altera o banco direto, sem passar pela aplicação.
    
    Corrija cada resposta e, no final, resuma as regras que evitam esses problemas.
  • Decidir o que vale a pena guardar

    Quero aprender a decidir se um dado deve ou não ir para o cache.
    
    Explique os critérios: frequência de leitura, custo de obter, frequência de mudança e tolerância a dado velho. Explique também o que é taxa de acerto e por que um cache com taxa baixa só acrescenta complexidade.
    
    Depois me apresente dez dados de um sistema de comércio eletrônico, um por vez (por exemplo: o catálogo de categorias, o preço exibido na listagem, o estoque no momento de finalizar a compra, as permissões do perfil do usuário, o resultado de uma busca popular, o saldo de pontos de fidelidade, a cotação de frete de uma transportadora externa, o carrinho do usuário, configurações do sistema e o relatório de vendas do dia). Para cada um, pergunte se eu guardaria em cache, com qual TTL e onde. Corrija as minhas respostas.