Caching: O Código Mais Rápido É o que Não Roda
Caching é a otimização de performance mais impactante. Uma resposta servida do cache é 10-1000x mais rápida que uma gerada do zero. Mas caching introduz complexidade: dados stale, invalidação e problemas de consistência.
As Camadas de Cache
Usuário → Cache Browser → CDN Edge → Cache Servidor (Redis) → App → Banco
~0ms ~20ms ~1ms ~50ms ~100ms
Cache do Browser (Cache-Control)
Cache-Control: public, max-age=3600 # 1 hora
Cache-Control: public, max-age=31536000, immutable # 1 ano (assets com hash)
Cache-Control: no-store # nunca cachear
Cache-Control: no-cache # cacheia mas sempre revalida
| Diretiva | Significado |
|---|
public | Qualquer cache pode armazenar (browser, CDN) |
private | Apenas o browser pode cachear (não CDN) |
max-age=N | Cachear por N segundos |
s-maxage=N | Duração do cache CDN |
stale-while-revalidate=N | Servir stale por N segundos enquanto busca nova versão |
immutable | Conteúdo nunca muda |
O Que Cachear Onde
| Conteúdo | Estratégia | Cache-Control |
|---|
| Assets estáticos | Cache longo + hash no nome | public, max-age=31536000, immutable |
| HTML estático | CDN com revalidação | public, s-maxage=3600, stale-while-revalidate=600 |
| Respostas API públicas | Cache CDN curto | public, s-maxage=60 |
| Respostas específicas do user | Private ou no-store | private, no-cache |
Cache Server-Side (Redis)
async function getProduct(id) {
const cached = await redis.get(`product:${id}`);
if (cached) return JSON.parse(cached);
const product = await db.products.findById(id);
await redis.set(`product:${id}`, JSON.stringify(product), 'EX', 300);
return product;
}
async function updateProduct(id, data) {
await db.products.update(id, data);
await redis.del(`product:${id}`); // invalida o cache
}
Invalidação de Cache (A Parte Difícil)
- Baseada em TTL: Cache expira após N segundos. Simples mas pode servir dados stale.
- Baseada em eventos: Invalidar quando dados mudam.
- Chaves versionadas:
product:42:v3 — incrementa versão no update. - Stale-while-revalidate: Serve stale imediatamente, atualiza em background.