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 dado | Tempo típico para obtê-lo |
|---|---|
| Memória do próprio processo | Menos de 1 microssegundo |
| Redis na mesma rede | Cerca de 0,2 a 1 milissegundo |
| Consulta simples ao banco, com índice | Cerca de 1 a 5 milissegundos |
| Consulta pesada, com agregações | Dezenas a centenas de milissegundos |
| Chamada a uma API externa | Dezenas 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:
| Camada | Exemplo | O que guarda |
|---|---|---|
| Navegador | Cache HTTP do navegador | Imagens, scripts, respostas com Cache-Control |
| CDN | Servidores perto do usuário | Arquivos estáticos e respostas públicas |
| Aplicação, em memória | Um mapa ou uma biblioteca de cache no processo | Dados muito lidos, por pouco tempo |
| Cache distribuído | Redis, Memcached | Dados compartilhados por todas as instâncias da aplicação |
| Banco de dados | Páginas de dados mantidas em memória | As 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ística | Por quê |
|---|---|
| É lido com frequência | Sem leituras repetidas, a taxa de acerto fica baixa |
| É caro de obter | Se a origem já é rápida, o ganho é pequeno |
| Muda pouco | Dados que mudam a todo segundo vivem expirando ou ficando velhos |
| Aceita ficar um pouco velho | Um 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.