Fundamentos9 min

Cache: benefícios e armadilhas

Cache pode acelerar dramaticamente seu sistema — ou criar problemas sutis e difíceis de debugar. Aprenda quando e como usar.

Cache é uma das técnicas mais poderosas para melhorar performance. Ao armazenar resultados de operações caras, evitamos repetir trabalho e reduzimos latência dramaticamente.

Mas cache não é mágica. Usado incorretamente, ele cria problemas sutis, difíceis de debugar e potencialmente graves. Este artigo explora os benefícios do cache, suas armadilhas, e como usá-lo de forma efetiva.

Cache é como sal na comida: a quantidade certa melhora tudo, demais estraga.

Por que Cache Funciona

O princípio da localidade

A maioria dos sistemas exibe padrões previsíveis:

  • Localidade temporal: dados acessados recentemente serão acessados novamente
  • Localidade espacial: dados próximos aos acessados também serão acessados

Se 80% das requisições acessam 20% dos dados (Pareto), cachear esses 20% tem impacto enorme.

Redução de latência

Sem cache:  App → Banco de dados → Resposta
            10ms + 50ms = 60ms

Com cache:  App → Cache hit → Resposta
            10ms + 1ms = 11ms

Melhoria de 5x ou mais é comum.

Redução de carga

Cada cache hit é uma requisição que não vai para:

  • Banco de dados
  • API externa
  • Processamento pesado

Níveis de Cache

1. Cache de CPU (L1, L2, L3)

Gerenciado pelo hardware. Você não controla diretamente, mas pode escrever código cache-friendly.

2. Cache de aplicação (in-memory)

const cache = new Map();

function getUser(id) {
    if (cache.has(id)) return cache.get(id);
    const user = fetchFromDB(id);
    cache.set(id, user);
    return user;
}

Prós: extremamente rápido, simples Contras: não compartilhado entre instâncias, perdido em restart

3. Cache distribuído (Redis, Memcached)

Compartilhado entre instâncias da aplicação.

Prós: compartilhado, persistente (com configuração), escalável Contras: latência de rede, mais complexo

4. Cache de CDN

Para conteúdo estático e páginas cacheáveis.

Prós: distribuído geograficamente, reduz carga no origin Contras: invalidação complexa

5. Cache de banco de dados

Query cache, buffer pool, etc. Gerenciado pelo banco.

As Armadilhas do Cache

1. Cache stampede (thundering herd)

Problema: quando uma entrada expira, múltiplas requisições simultâneas tentam recalculá-la.

Cache expira
    ↓
100 requisições chegam
    ↓
Todas vão para o banco
    ↓
Banco sobrecarregado

Soluções:

  • Locking (apenas um recalcula, outros esperam)
  • Refresh antecipado (antes de expirar)
  • Probabilistic early expiration

2. Dados desatualizados (stale data)

Problema: cache mostra dados que já mudaram na fonte.

Soluções:

  • TTL adequado ao caso de uso
  • Invalidação explícita em writes
  • Cache-aside pattern com invalidação

3. Cache inconsistente entre instâncias

Problema: cache local diferente em cada servidor.

Servidor A: user.name = "João"
Servidor B: user.name = "Maria" (atualizado)

Soluções:

  • Usar cache distribuído
  • TTL curto para dados voláteis
  • Pub/sub para invalidação

4. Memory pressure

Problema: cache cresce até consumir toda memória.

Soluções:

  • Limitar tamanho do cache
  • Política de evicção (LRU, LFU)
  • Monitorar uso de memória

5. Cache de dados que não deveria cachear

Problema: cachear dados sensíveis ou específicos de usuário incorretamente.

Riscos:

  • Vazamento de dados entre usuários
  • Problemas de LGPD/GDPR
  • Comportamento incorreto

6. Cold start

Problema: após deploy ou restart, cache está vazio.

Soluções:

  • Warm-up proativo
  • Degradação graceful
  • Rolling deploys

Estratégias de Cache

Cache-Aside (Lazy Loading)

function getData(key) {
    let data = cache.get(key);
    if (!data) {
        data = database.get(key);
        cache.set(key, data, ttl);
    }
    return data;
}

Prós: simples, dados cacheados sob demanda Contras: primeira requisição sempre lenta

Write-Through

function saveData(key, data) {
    database.save(key, data);
    cache.set(key, data, ttl);
}

Prós: cache sempre atualizado Contras: writes mais lentos

Write-Behind (Write-Back)

function saveData(key, data) {
    cache.set(key, data);
    // Persiste assincronamente depois
    queue.push({ key, data });
}

Prós: writes muito rápidos Contras: risco de perda de dados, complexo

Refresh-Ahead

Cache é atualizado automaticamente antes de expirar.

Prós: evita cache miss, latência consistente Contras: pode atualizar dados não acessados

Métricas Essenciais

Hit rate

Hit rate = cache hits / (cache hits + cache misses)

Bom: > 90% Ótimo: > 95% Ruim: < 80% (reconsidere a estratégia)

Latência de cache

Cache muito lento pode não valer a pena. Meça:

  • Tempo de leitura
  • Tempo de escrita
  • Latência de rede (distribuído)

Eviction rate

Muitas evições indicam cache pequeno demais ou TTL muito longo.

Boas Práticas

1. Defina TTL apropriado

Tipo de dado TTL sugerido
Configuração 5-15 minutos
Dados de catálogo 1-5 minutos
Sessão de usuário 30 minutos
Dados calculados Depende da frequência de mudança

2. Use keys estruturadas

user:123:profile
product:456:inventory
search:hash(query)

3. Serialize eficientemente

JSON é legível mas lento. Para alto volume, considere:

  • MessagePack
  • Protocol Buffers
  • Avro

4. Monitore sempre

  • Hit rate por tipo de cache
  • Latência
  • Uso de memória
  • Evictions

5. Tenha fallback

try {
    return cache.get(key);
} catch (e) {
    // Cache indisponível, vai direto na fonte
    return database.get(key);
}

Quando NÃO Usar Cache

  • Dados que mudam a cada requisição
  • Dados muito grandes (custo de serialização)
  • Hit rate esperado muito baixo
  • Quando consistência forte é mandatória
  • Quando a fonte já é rápida o suficiente

Conclusão

Cache é uma ferramenta poderosa, mas requer cuidado:

  1. Entenda seus padrões de acesso antes de cachear
  2. Escolha a estratégia certa para cada caso
  3. Configure TTL adequado — nem muito curto nem muito longo
  4. Prepare-se para falhas — cache indisponível não pode derrubar o sistema
  5. Monitore continuamente — hit rate, latência, memória

Usado corretamente, cache pode transformar um sistema lento em um sistema rápido. Usado incorretamente, pode criar bugs sutis e problemas de escala.

Cache é uma troca: você troca consistência por velocidade. Certifique-se de que a troca vale a pena.

cacheperformancearquiteturaredis
Compartilhar:
Read in English

Quer entender os limites da sua plataforma?

Entre em contato para uma avaliação de performance.

Fale Conosco