| Camada | Guarda | Invalidado por | BoxOffice |
|---|---|---|---|
| Cliente (navegador, app) | respostas HTTP (Cache-Control, ETag) |
só cabeçalhos — não dá para recolher | JS versionado, JSON do evento max-age=10 |
| CDN | estáticos, páginas públicas | API de purge, URLs versionadas | pôsteres, página pública do evento |
| API gateway | respostas GET inteiras |
TTL curto | GET /events/42 por 5 s |
| Em processo (Caffeine) | objetos quentes no heap | cada réplica separadamente | geometria do local |
| Distribuído (Redis, Valkey) | objetos, resultados, sessões | app (remoção) + TTL | detalhes do evento, busca |
| Banco de dados | páginas no buffer pool | o motor — sempre consistente | páginas do índice de seats |
Mais perto do usuário: mais rápido e mais barato por acerto, porém mais difícil de invalidar.
| Taxa de acerto | Latência efetiva (0,5 / 8,5 ms) | Carga no banco com 50.000 leituras/s |
|---|---|---|
| 90% | 1,3 ms | 5.000 QPS |
| 99% | 0,58 ms | 500 QPS |
| 99,9% | 0,51 ms | 50 QPS |
Pense na taxa de falta: cada nove a mais é 10× menos carga no banco.
MEMORY USAGE); acompanhe despejos vs taxa de acerto; deixe folga.Cacheie o que você exibe, não aquilo sobre o que você decide. O mapa de assentos pode ter 1 s de defasagem; a reserva do assento é decidida numa transação SQL. O mesmo vale para preços no checkout, pagamentos, saldos.
Leitura: GET → acertou? devolve. Falta → lê o banco → SET key EX ttl → devolve.
Escrita: atualiza o banco → commit → DEL key.
@Cacheable(cacheNames = "events", key = "#id")
public EventDto findById(long id) { ... }
@CacheEvict(cacheNames = "events", key = "#id") // after commit!
public EventDto update(long id, EventUpdate change) { ... }
| Padrão | Ideia | Bom | Risco | BoxOffice |
|---|---|---|---|---|
| Read-through | o cache carrega na falta | agrupa faltas concorrentes | — | geometria do local (Caffeine) |
| Write-through | escreve cache + banco juntos | leituras frescas após escritas | duas escritas, não atômicas | painel do organizador |
| Write-behind | cache agora, banco depois | escritas na velocidade da memória | perde escritas confirmadas | contadores de visualização |
| Write-around | escreve no banco, pula o cache | sem poluição | primeira leitura erra | ingressos, histórico de pedidos |
| Refresh-ahead | recarrega antes de expirar | chaves quentes nunca erram | atualizações desperdiçadas | aberturas de venda de hoje |
Write-behind para reservas de assento = venda dupla depois de uma falha do cache.
boxoffice:catalog:event:42:v3.| Dado | Defasagem aceitável | Mecanismo |
|---|---|---|
| Descrição do evento | ~1 min | remoção na escrita + TTL 5 min |
| Tabela de preços | segundos | TTL 30 s + remoção; o checkout lê o banco |
| Mapa de assentos (exibição) | 1–2 s | TTL 1 s |
| Perfil do usuário | read-your-writes para o dono | remoção + desvio do cache para quem escreveu |
| Reserva, pedido, pagamento | zero | não cacheado |
Decida o orçamento por tipo de dado com o time de produto; o mecanismo decorre dele.
v1 → escritor confirma v2 + DEL → leitor faz SET v1.DEL + pub/sub para o L1.| Política | Mantém | Fraqueza |
|---|---|---|
| LRU | os usados recentemente | uma varredura expulsa o conjunto quente |
| LFU | os usados com frequência | demora a esquecer (precisa envelhecer) |
| FIFO / aleatória | — | ignoram a popularidade |
| W-TinyLFU (Caffeine) | admitidos por frequência + pequena janela LRU | mais complexa |
allkeys-lru / allkeys-lfu para caches; noeviction para sessões e locks.maxmemory-samples 5).| Falha | Sintoma | Correção |
|---|---|---|
| Cache frio | o banco recebe tudo após reinício/deploy | aquecimento, deslocamento gradual |
| Stampede | chave quente expira, N consultas idênticas | agrupamento, lock, SWR, XFetch |
| Avalanche | muitas chaves expiram juntas | jitter no TTL |
| Penetração | ids que não existem | cache negativo, filtro de Bloom |
| Chave quente | um nó satura | cache L1, replicação da chave |
| Cache fora | o banco dimensionado para as faltas recebe 100% | timeouts, breaker, descarte de carga |
event:42: 20.000 leituras/s; recalcular leva 200 ms. A chave expira. Quantas consultas idênticas chegam ao banco?
SET lock:key token NX PX 5000; as perdedoras esperam e releem.Recalcule se
Sem locks, sem coordenação: o algoritmo se adapta ao tráfego.
Chave quente: 400.000 leituras/s × 4 KB ≈ 13 Gbit/s num nó só.
event:42#0..7, CDN para a parte estática.Cache fora: o banco foi dimensionado para as faltas.
Quando o banco depende da taxa de acerto, o cache é uma dependência que sustenta carga.
MULTI/EXEC (sem rollback), scripts Lua / functions.everysec) · ambos.slot = CRC16(key) mod 16384; cada primário é dono de uma faixa.MOVED / ASK redirecionam quando ele muda.{event:42}:seats, {event:42}:prices.{boxoffice}:* coloca a aplicação inteira num nó — use como tag algo com muitos valores.
> SET hold:42:A-12 fan:1017 NX PX 600000
OK
> SET hold:42:A-12 fan:2203 NX PX 600000
(nil)
Se o Redis perder uma pré-reserva, dois fãs chegam ao banco e um perde lá. A correção nunca dependeu do Redis.
| Componente | Pergunta que responde | Conceitos-chave |
|---|---|---|
client mobile |
o dispositivo pode pular a requisição? | Cache-Control, ETag, assets versionados |
cdn apigw |
a borda pode responder pela origem? | páginas públicas, TTLs curtos, purge por tag |
app |
cada réplica pode manter os objetos mais quentes? | L1 em processo, cache em dois níveis |
cache |
uma cópia compartilhada absorve a maioria das leituras? | cache-aside, TTL, despejo, taxa de acerto, dimensionamento |
cache (sob estresse) |
chave quente expira? o cache cai? | stampede, avalanche, chaves quentes, fallback |
sql |
o que o cache protege? | fonte da verdade — cacheie o que exibe, não aquilo com que decide |
stream pubsub |
como uma mudança chega a todas as cópias? | CDC a partir do WAL, broadcast para o L1 |
Cada camada é mais rápida e mais perto do usuário, mas guarda menos e é mais difícil de invalidar.
Roteiro: (1) por que caches funcionam e onde ficam; (2) a matemática da taxa de acerto e o dimensionamento; (3) padrões; (4) invalidação e despejo; (5) modos de falha; (6) Redis.
Deixe a turma responder primeiro. Leve-os a: o trabalho é redundante, então elimine-o.
Desenhe a corrida no quadro como uma linha do tempo de quatro passos.