Configuração de CDN: cache policies e invalidação

1. Fundamentos de CDN e Cache Policies

Uma Content Delivery Network (CDN) é uma rede distribuída de servidores que armazena em cache conteúdo estático e dinâmico próximo aos usuários finais, reduzindo latência e carga no servidor de origem. O funcionamento depende de cache policies — regras que definem por quanto tempo e em quais condições o conteúdo deve ser armazenado.

O principal mecanismo de controle é o TTL (Time-To-Live), que determina o tempo máximo que um recurso permanece válido no cache. As políticas de cache se dividem em três categorias:

  • Cache público: conteúdo acessível a qualquer usuário, armazenado em servidores de borda (edge)
  • Cache privado: conteúdo específico por usuário, armazenado apenas no navegador
  • Cache de borda: armazenamento temporário nos PoPs (Points of Presence) da CDN

Headers HTTP como Cache-Control e Expires são os mecanismos fundamentais para implementar essas políticas.

2. Configuração de Headers de Cache no Servidor de Origem

O header Cache-Control é o padrão moderno para controle de cache. Suas diretivas principais:

# Arquivos estáticos com cache longo (1 ano)
Cache-Control: public, max-age=31536000, immutable

# Conteúdo dinâmico com cache curto (5 minutos)
Cache-Control: public, max-age=300, s-maxage=600

# Conteúdo privado (não armazenar em CDN)
Cache-Control: private, max-age=0

# Sem cache (para dados sensíveis)
Cache-Control: no-cache, no-store, must-revalidate

O header Expires (obsoleto, mas ainda usado) define uma data absoluta:

Expires: Wed, 21 Dec 2025 07:28:00 GMT

Quando usar cada um:
- Cache-Control para controle granular e revalidação
- Expires como fallback para clientes HTTP/1.0
- Sempre prefira Cache-Control em sistemas modernos

Exemplo prático para servidor Nginx:

# Configuração de cache para arquivos estáticos
location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg)$ {
    expires 365d;
    add_header Cache-Control "public, immutable, max-age=31536000";
}

# Configuração para HTML dinâmico
location /api/ {
    add_header Cache-Control "public, max-age=60, s-maxage=120";
}

3. Estratégias de Cache por Tipo de Conteúdo

Conteúdo estático

Arquivos CSS, JS, imagens e fontes devem usar TTLs longos combinados com versionamento:

# Exemplo: style.v2.css → cache por 1 ano
Cache-Control: public, max-age=31536000, immutable

Conteúdo dinâmico

APIs e páginas HTML com atualizações frequentes usam TTLs curtos e stale-while-revalidate:

Cache-Control: public, max-age=60, stale-while-revalidate=300

Essa diretiva permite servir conteúdo obsoleto por até 5 minutos enquanto o cache é atualizado em segundo plano.

Conteúdo personalizado

Para conteúdo que varia por usuário, use o header Vary:

# Varia por cookie de autenticação e idioma
Vary: Cookie, Accept-Language
Cache-Control: private, max-age=0

4. Invalidação de Cache: Métodos e Boas Práticas

A invalidação remove conteúdo do cache antes do TTL expirar. Os principais métodos são:

Invalidação por URL (purge)

Remove objetos específicos:

# Exemplo com Cloudflare API
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/purge_cache" \
  -H "Authorization: Bearer API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{"files":["https://exemplo.com/style.css","https://exemplo.com/script.js"]}'

Invalidação por tag

Limpa conteúdo relacionado em lote:

# Invalidação por tag no AWS CloudFront
aws cloudfront create-invalidation \
  --distribution-id DISTRIBUTION_ID \
  --paths "/*" \
  --caller-reference "deploy-2025-01-15"

Invalidação automatizada com webhooks

# Script Python para purge automático via webhook
import requests

def purge_cache(urls):
    webhook_url = "https://api.cdn.com/purge"
    payload = {"urls": urls}
    headers = {"Authorization": "Bearer token"}
    response = requests.post(webhook_url, json=payload, headers=headers)
    return response.status_code

# Uso: purge_cache(["/css/main.css", "/js/app.js"])

5. Cache Policies Avançadas e Otimização

Cache-Control: immutable

Indica que o recurso nunca muda entre versões:

Cache-Control: public, max-age=31536000, immutable

Cache hierarchy (edge, regional, origin shield)

# Configuração de cache em camadas
Edge cache:     TTL = 1 hora
Regional cache: TTL = 4 horas
Origin shield:  TTL = 24 horas

Compressão com cache

# Habilitar compressão gzip/brotli com cache
Content-Encoding: br
Cache-Control: public, max-age=86400
Vary: Accept-Encoding

6. Monitoramento e Troubleshooting de Cache

Headers de diagnóstico essenciais:

# Headers retornados pela CDN
X-Cache: HIT (do servidor de borda)
Age: 3600 (tempo em cache em segundos)
CF-Cache-Status: HIT (Cloudflare)

Análise de hit ratio:
- Hit ratio > 90%: configuração eficiente
- Hit ratio < 70%: revisar TTLs e políticas
- Miss frequente: verificar headers de origem

Ferramentas de debugging:

# curl para verificar headers de cache
curl -I https://exemplo.com/style.css -H "Accept-Encoding: gzip"

# Browser DevTools: Network tab → Headers → Cache-Control

7. Casos Práticos e Cenários de Configuração

Exemplo 1: Site estático com cache agressivo

# Configuração para site Jekyll/Hugo
Cache-Control para arquivos estáticos:
- CSS/JS versionados: max-age=31536000, immutable
- Imagens: max-age=2592000 (30 dias)
- HTML: max-age=3600 (1 hora)

Purge automático após deploy:
- Script CI/CD que invalida / e /assets/*
- Webhook para CDN após cada push

Exemplo 2: API com cache dinâmico

# API REST com cache por endpoint
GET /api/produtos
Cache-Control: public, max-age=60, stale-while-revalidate=300

GET /api/produtos/123
Cache-Control: public, max-age=300

POST /api/produtos
Cache-Control: no-cache, no-store

Invalidação por tag:
- Tag: "produtos:lista" para /api/produtos
- Tag: "produtos:123" para /api/produtos/123

Exemplo 3: Aplicação com autenticação

# Conteúdo público (login page)
Cache-Control: public, max-age=3600

# Conteúdo autenticado
Cache-Control: private, max-age=0
Vary: Cookie, Authorization

# Dashboard do usuário
Cache-Control: private, max-age=60
Vary: Cookie

Referências