Aquela famosa citação "Existem apenas duas coisas difíceis na Ciência da Computação: invalidação de cache e nomenclatura de coisas" reflete a realidade. O cache é, simultaneamente, a otimização de desempenho mais impactante e a mais complexa de implementar corretamente. Se bem feito, o cache pode tornar seu site 10 a 100 vezes mais rápido. Se mal executado, ele serve dados desatualizados aos seus usuários.

As Camadas do Cache

Uma requisição web típica passa por diversas camadas de cache:

  • Cache do Navegador: O mais próximo do usuário. Armazena recursos localmente no dispositivo dele.
  • Cache de CDN: Servidores de borda distribuídos globalmente. Serve o conteúdo da localização geográfica mais próxima.
  • Cache de Proxy Reverso: Nginx, Varnish ou Cloudflare posicionados na frente do seu servidor de aplicação.
  • Cache da Aplicação: Armazenamentos em memória como Redis ou Memcached para resultados de consultas ao banco de dados, respostas de API e valores computados.
  • Cache do Banco de Dados: Cache de consulta e pool de buffer embutidos no motor do banco de dados.

Headers de Cache do Navegador

Header Cache-Control
# Ativos estáticos (CSS, JS, imagens) — cache agressivo
Cache-Control: public, max-age=31536000, immutable

# Páginas HTML — não cachear, sempre revalidar
Cache-Control: no-cache

# Respostas de API — cachear por 5 minutos
Cache-Control: private, max-age=300

# Dados sensíveis — nunca cachear
Cache-Control: no-store

Diretivas Chave

  • public — Pode ser cacheado por navegadores E caches intermediários (CDNs, proxies).
  • private — Apenas o navegador do usuário pode cacheá-lo (não CDNs).
  • max-age=N — Cachear por N segundos.
  • no-cache — Cachear, mas sempre revalidar com o servidor antes de usar.
  • no-store — Não cachear de forma alguma. Use para dados sensíveis.
  • immutable — O conteúdo nunca mudará (usado com nomes de arquivo com hash).

Quebra de Cache com Nomes de Arquivo Fingerprinted

A estratégia ideal de cache para ativos estáticos: dê aos arquivos um hash único no nome do arquivo e cacheie-os para sempre.

Ativos Fingerprinted
<!-- Em vez disso (pesadelo de invalidação de cache): -->
<link rel="stylesheet" href="/pt/css/style.css">

<!-- Use isto (infinitamente cacheável): -->
<link rel="stylesheet" href="/pt/css/style.a3f9b2c1.css">

<!-- Quando o CSS muda, o hash muda, então o navegador
     busca o novo arquivo automaticamente -->

Ferramentas de build como Vite, Webpack e esbuild geram esses nomes de arquivo fingerprinted automaticamente.

Cache em CDN

Uma CDN (Content Delivery Network) armazena seu conteúdo em servidores de borda ao redor do mundo. Quando um usuário em Tóquio solicita sua imagem, ela é servida de um servidor em Tóquio, em vez do seu servidor de origem em Londres.

  • Ativos estáticos: Cache na borda da CDN com max-age longo + nomes de arquivo fingerprinted.
  • Páginas HTML: Cachear com TTL curto (ex: 60 segundos) ou usar stale-while-revalidate.
  • Respostas de API: Cachear requisições GET para dados públicos, nunca cachear POST/PUT/DELETE.

Cache no Lado do Servidor com Redis

Padrão de Cache Redis (Node.js)
import Redis from 'ioredis';
const redis = new Redis();

async function getUser(userId) {
  const cacheKey = `user:${userId}`;

  // 1. Verifique o cache primeiro
  const cached = await redis.get(cacheKey);
  if (cached) return JSON.parse(cached);

  // 2. Cache miss — consulte o banco de dados
  const user = await db.query('SELECT * FROM users WHERE id = $1', [userId]);

  // 3. Armazene no cache (expire em 5 minutos)
  await redis.set(cacheKey, JSON.stringify(user), 'EX', 300);

  return user;
}

// Invalide na atualização
async function updateUser(userId, data) {
  await db.query('UPDATE users SET ... WHERE id = $1', [userId]);
  await redis.del(`user:${userId}`); // Limpe o cache
}

Estratégias de Invalidação de Cache

  • TTL (Time-To-Live): O cache expira após um tempo fixo. Simples, mas pode servir dados desatualizados.
  • Write-Through: Atualize o cache sempre que atualizar o banco de dados. Consistente, mas adiciona latência de escrita.
  • Write-Behind: Atualize o cache imediatamente, envie para o banco de dados assincronamente. Rápido, mas arriscado.
  • Cache-Aside: A aplicação gerencia o cache manualmente (o exemplo do Redis acima). Padrão mais comum.
  • Orientado a Eventos: Mudanças no banco de dados emitem eventos que invalidam caches relevantes. Mais robusto para sistemas distribuídos.

Experimente Nossas Ferramentas de Desempenho Gratuitas

Minifique seu CSS, JavaScript e HTML para reduzir o tamanho dos arquivos.