O que é cache e por que ele existe
Cache é basicamente memória rápida que guarda dados para evitar processamento repetido. Todo sistema que precisa responder rápido tem algum tipo de cacheado no caminho. Sem cache, cada requisição teria que reconstruir a resposta do zero — buscar no banco, calcular, formatar. Isso funciona em laboratório, mas não escala. Acho que todo mundo já passou por um sistema que lenta de repente só porque alguém removeu o cache sem avisar. Já vi isso acontecendo numa aplicação de e-commerce quando a equipe de infraestrutura reiniciou um serviço de cache sem colocar no calendário de mudanças. O banco de dados caiu em 400ms de média e levou 2 segundos. Os usuários reclamaram que o carrinho demorava para carregar. Nada grave, mas suficiente para gerar ticket.
Tipos de cacheado mais comuns
Existem camadas de cache que funcionam de formas bem diferentes. Não dá pra tratar todas iguais.
Cache de navegador (browser cache)
É o mais simples e o mais ignorado. O navegador guarda arquivos estáticos — CSS, JavaScript, imagens — num disco local. Na próxima visita, ele pede ao servidor se o arquivo mudou. O servidor responde com 304 Not Modified e pronto. Sem download. O problema real aqui é a invalidação. Você atualiza um arquivo CSS, faz deploy, e metade dos usuários ainda vê a versão antiga porque o navegador respeita o Cache-Control ou o Expires que estava configurado semanas antes. Eu resolvi isso num projeto usando hash no nome do arquivo. Em vez de app.js, vira app.a3f9c2d1.js. Quando o conteúdo muda, o hash muda, e o navegador é obrigado a baixar de novo. Funciona, mas exige configuração no build.
Headeres como ETag e Cache-Control controlam esse comportamento. Vários times configuram errado e deixam cache infinito em arquivos que mudam frequentemente. O resultado é o mesmo: usuário reclamando que a interface não atualiza.
Cache de servidor (application cache)
Aqui os dados ficam na memória do próprio servidor ou num serviço separado como Redis ou Memcached. Consultas frequentes ao banco são substituídas por leituras em memória. A latência cai de milissegundos para microssegundos. Redis é a escolha padrão há anos. Ele suporta estruturas de dados avançadas, expiração, pub/sub. Mas tem um detalhe que muita gente esquece: Redis é single-threaded para operações básicas. Se você fazer um BLPOP em chave grande enquanto outro cliente roda um KEYS *, o serviço trava. Sempre use SCAN em vez de KEYS em produção. Já vi isso derrubando uma API inteira num horário de pico.
O custo é manutenção. Cache invalidation é um dos problemas mais difíceis em engenharia de software. Você precisa decidir quando os dados cached ficam inválidos. TTL fixo funciona para dados que não precisam estar atualizados em tempo real. Para dados sensíveis, invalidação sob demanda ou write-through é mais seguro, mas mais complexo.
👉 Clique no botão abaixo para saber mais sobre o assunto!
Cache de CDN
Content Delivery Network guarda cópias do seu conteúdo em servidores geograficamente distribuídos. O usuário baixa do servidor mais perto, não do seu datacenter original. Isso reduz latência e carga no servidor principal. A CDN funciona bem para conteúdo estático e até para respostas de API que não mudam spesso. Mas tem uma armadilha: se você configurar TTL alto na CDN e precisar invalidar rapidamente, o processo pode levar minutos. A Cloudflare e a AWS CloudFront têm endpoints de purge, mas cada requisição de purge tem custo e limitação de taxa. Em um projeto anterior, precisamos invalidar 50 mil URLs rapidamente após um erro de deploy. Levou 12 minutos porque o purge é processado em fila.
Para conteúdo dinâmico, muitas CDNs oferecem cache inteligente que avalia se a resposta realmente precisa ser armazenada. Isso evita enchergar a CDN de dados que mudam a cada requisição.
Cache de banco de dados
Quase todo SGBD moderno tem cache interno. MySQL usa query cache (removido no 8.0 por problemas de concorrência). PostgreSQL usa shared buffers. O Oracle tem buffer cache. Esse cache é gerenciado automaticamente pelo banco, então você não configura diretamente, mas precisa entender como ele funciona para não sabotá-lo. O erro comum é subestimar o cache de banco e fazer consulta desnecessária. Uma query mal indexada que causa full scan não vai ganhar nada com cache externo. Primeiro resolve a query, depois pensa em cache.
Cache de objeto e método
Em linguagens como Java, Python ou C#, é possível cache resultado de funções ou métodos inteiros. Annotation como @Cacheable no Spring guarda o retorno de um método baseado nos argumentos. Na próxima chamada com os mesmos parâmetros, o método nem é executado. Isso é poderoso, mas fácil de usar errado. Se o método tem efeito colateral ou depende de estado externo que muda, o cache retorna dado obsoleto. Eu vi um sistema de cálculo de frete que usava @Cacheable com TTL de 5 minutos. Uma promoção relâmpago mudou as tarifas, e o cache reteve o valor antigo. O prejuízo foi de R$ 12 mil em pedidos com frete incorreto antes de alguém perceber.
Layering e conflito de cache
Quando você tem múltiplos tipos de cacheado em camadas diferentes, eles podem conflitar. O navegador cacheou uma resposta, a CDN cacheou outra, e o servidor de aplicação tem um terceiro cache. Qual é a fonte da verdade? A regra prática é: cache sempre da camada mais externa para a mais interna, e invalide na mesma ordem. Se você atualiza um dado, invalide a CDN primeiro, depois o cache de aplicação, depois o banco. Inverter essa ordem cria inconsistências temporárias que são difíceis de debugar.
Métricas que importam
Hit rate é a métrica básica. Quantas requisições foram atendidas pelo cache versus quantas foram para a origem. Um hit rate acima de 90% é bom para dados pouco mutáveis. Abaixo de 50%, o cache pode estar mais atrapalhando do que ajudando, especialmente se a invalidação for complexa. Latência média economizada também é útil. Se o cache reduz o tempo de resposta de 200ms para 5ms, mas só acontece 10% das vezes, o ganho real é de 18ms médios. Em alguns casos, otimizar a query original dá mais retorno do que adicionar uma camada de cache.
Quando não usar cache
Dados financeiros em tempo real. Situações que exigem consistência forte. Sistemas com baixa repetição de acesso onde o overhead do cache é maior que o custo da operação direta. Cache adiciona complexidade. Se o problema é simples, não adicione uma camada que vai precisar ser mantida. Existem alternativas como materialized views no banco ou query optimization que resolvem parte do mesmo problema sem o custo adicional de invalidação.