← Blog

Cache: o que guardar e o que invalidar

A query de ranking leva cinco segundos. O reflexo é Cache::remember. Trinta segundos depois, a mesma request volta em dezenas de milissegundos. O gráfico bonito esconde a pergunta que vai doer: quando esse valor deixa de ser verdade — e quem avisa o cache?

Cache é cópia. Cópia fica velha. O difícil nunca foi guardar. Foi decidir o que é copiável e como a cópia morre.

O que vale a pena guardar

Guarde o que é caro de obter e estável o bastante para o usuário aceitar um atraso de atualização. Agregado de avaliação, HTML de página pública, resposta de API de terceiro com cota, lista de categorias, configuração que muda uma vez por semana. O ganho é não repetir o custo.

Não guarde o que já é barato. Cache na frente de um SELECT por chave primária, com índice, em disco quente, adiciona Redis, serialização e um modo novo de estar errado. Otimize a query. Cache não é desculpa para N+1.

Com vários servidores, cache em memória do processo (APCu, array estático) mente: o nó A invalida, o B serve o velho. Cache distribuído — Redis, Memcached — é o que torna a cópia um componente, não um acidente de processo. Você paga RAM rápida e mais um ponto para operar. Em troca, todos os nós veem o mesmo valor, ou pelo menos o mesmo TTL.

TTL (tempo de vida) é o palpite honesto: “este ranking pode ter até 30 s de atraso”. Palpite bom vem do negócio, não do default do framework. Página de produto que muda preço na hora não é ranking de especialistas da semana.

flowchart TD
  A[Dado pedido] --> B{É caro e estável?}
  B -->|Não| C[Buscar na origem]
  B -->|Sim| D{Pode atrasar?}
  D -->|Não| C
  D -->|Sim| E{Como morre a cópia?}
  E -->|TTL basta| F[Cache com expiração]
  E -->|Precisa do evento| G[Invalidar no write]
  E -->|Não sei invalidar| C
  classDef ouro fill:#FBF5E4,stroke:#C9A227,color:#0B1F18,stroke-width:1.4px
  classDef verde fill:#F3FAF7,stroke:#1E7A57,color:#0B1F18,stroke-width:1.4px
  classDef fim fill:#14513B,stroke:#0F3328,color:#FBFAF6,stroke-width:1.4px
  class A,B,D ouro
  class E,F,G verde
  class C fim

Invalidação é o trabalho de verdade

Há três famílias, e misturá-las sem regra é incidente.

TTL só. Simples. Eventualmente consistente. Serve para dado que pode atrasar. Não serve para “o usuário acabou de publicar e não se vê”.

Invalidar no write. No mesmo fluxo que grava a origem, você apaga (ou atualiza) a chave. Correto quando o write é o único caminho. Falso quando existe admin, job, SQL manual, sync de ERP. O cache vira verdade paralela.

Versionar chave. produto:42:v7. O write incrementa versão. Leitores pegam a nova. Evita alguns races de delete/set. Exige disciplina de chave. Não apaga o problema de “quem incrementa”.

Stampede (mil requests recalculando o miss ao mesmo tempo) é o primo do TTL curto em dado caro. Lock de recálculo, grace period, prefill em job: ferramentas. Se o recálculo leva cinco segundos, não deixe o miss da request do usuário ser o recálculo. Prefira fila que aquece a chave.

A pergunta de desenho é: quem é o dono da verdade, e em que instante a cópia pode divergir? Se você não responde, o cache é um bug com SLA de performance.

O que nunca (ou quase nunca) cachear

Autorização. “Pode este usuário ver este recurso?” muda com papel, time, recurso revogado, sessão encerrada. Servir 200 de um cache antigo é vazamento. 403 antigo é suporte. Permissão pertence ao request atual, talvez com um lookup rápido e indexado, não com uma página HTML pública reutilizada entre usuários. Cuidado especial com cache de proxy (CDN, Nginx) em página autenticada: um Cache-Control errado publica o painel do cliente A no cliente B.

Dinheiro em movimento. Saldo, limite, posição de estoque no checkout, status de pagamento. Atraso aqui não é “ranking um pouco velho”. É oversell, double spend, comprovante mentiroso. Leia a origem transacional. Se precisar de velocidade, o caminho é modelo de dado e índice, não TTL de 10 s no saldo.

Relatório único e “em tempo real”. Compliance, auditoria, extrato, relatório que o usuário gera para enviar a um órgão. O requisito costuma ser “os dados mais recentes” ou “exatamente esta fotografia com carimbo”. Cache mente nos dois. Relatório pesado vai para job, não para Redis com a query de cinco segundos.

Há zona cinzenta: catálogo de produto cujo preço muda de hora em hora pode ter cache curto se o checkout relê o preço na origem. A página pode atrasar. A cobrança não.

Tipo de dado Cache? Por quê
Ranking público, agregação cara Sim, com TTL explícito Atraso aceitável
HTML anônimo Sim, CDN + TTL Alta leitura, pouca variação
Permissão / papel Não (ou TTL minúsculo com medo) Revogação tem que valer agora
Saldo, pagamento, estoque de checkout Não Cópia vira dinheiro errado
Extrato, relatório oficial Não Fotografia tem que ser da origem
Config rara Sim, invalidar no write Write é caminho único

Chave, hit e honestidade

Chave ruim é cache inútil: esquecer o limit, o idioma, o usuário, a versão do schema. Hit alto em chave errada é pior do que miss. Inclua na chave tudo que muda o resultado, e nada que não mude. highest_rated:10 não é highest_rated:50.

Meça hit ratio, mas não idolatre. 99% de hit em dado que não deveria estar no cache é 99% de mentira eficiente. Olhe também idade da chave, taxa de invalidação, tempo de recálculo, erros de desserialização.

Opcache e HTTP cache são primos, não o mesmo bicho. Bytecode no processo não substitui Redis de ranking. CDN não substitui autorização. Cada camada copia uma coisa. Nomeie a camada quando for discutir “vamos cachear”.

Uma regra para a próxima chave

  1. Qual o custo da origem e o atraso máximo que o negócio aceita?
  2. Qual evento torna a cópia falsa?
  3. Esse evento passa pelo mesmo código que eu controlo?
  4. Se a resposta a (3) for não, TTL conservador ou não cacheie.
  5. Se for dinheiro, permissão ou relatório único, pare no passo (1) e não crie a chave.

Cache bom é decisão de produto disfarçada de infraestrutura. TTL é o acordo de atraso. Invalidação é o acordo de verdade. Sem os dois, você só comprou RAM para servir o passado com confiança.

Fila, cache e API no mesmo projeto aparecem no PHP One volume 2, quando a Casa Amarela deixa de caber no request síncrono.

Leia também: Mensageria: por que filas melhoram a resposta e Load balancer, Nginx e vários servidores.

#Cache#Performance#Arquitetura#Dados

Thiago Nogueira

Autor de A Caixa Mágica e das séries Programming One e AI One na Editora Pensar Bem.

Capa de Python One

Python One

Do primeiro print à API REST em produção.