Decisão: qual estratégia de cache?
Um cache mantém os dados lidos com frequência em uma camada rápida à frente do banco (ex.: Redis), reduzindo a latência e a carga do banco. Mas nem todos os dados são adequados para cache, e uma invalidação errada cria risco de dados defasados/incorretos. Esta árvore primeiro verifica se você realmente precisa de cache e depois ajuda a escolher entre cache-aside, read-through, write-through e write-behind com base no padrão de leitura/gravação, além de tratar da prevenção de stampedes.
Como é a sua carga: predominam leituras ou gravações?
Um cache compensa mais quando os mesmos dados são lidos muitas vezes (muitas leituras) e não mudam com frequência. Primeiro, estabeleça o padrão geral: os dados são muito lidos e raramente alterados, são atualizados constantemente, ou você não tem certeza se vale a pena adicionar um cache?
- Muitíssimas leituras, os dados mudam relativamente pouco
- As gravações também são intensas; os dados gravados são lidos imediatamente/com frequência
- Não tenho certeza; eu realmente preciso de cache?
Quem deve ser responsável por popular o cache?
Em um cenário com muitas leituras, a escolha-chave é quem popula o cache. Sua aplicação deve gerenciar o cache explicitamente e recorrer ela mesma ao banco (alta flexibilidade), ou a camada de cache deve buscar os dados no banco subjacente em caso de miss e retorná-los de forma transparente?
- Deixar a aplicação gerenciar explicitamente; quero flexibilidade e controle
- Deixar a camada de cache buscar no banco em caso de miss (transparente)
Nas gravações, a prioridade é a consistência ou a velocidade de gravação?
Se as gravações forem intensas, você precisa decidir quão consistentes os dados gravados serão entre o cache e o banco. O cache e o banco devem ser atualizados juntos a cada gravação para garantir consistência (gravações um pouco mais lentas), ou as gravações devem ir primeiro ao cache e ser aplicadas ao banco de forma assíncrona em segundo plano (gravações muito rápidas, mas com risco de perda)?
- A consistência importa; as leituras devem estar sempre atualizadas
- A velocidade de gravação é crítica; consistência levemente atrasada e risco de perda são aceitáveis
Recomendação: não adicione cache por enquanto
Um cache não é gratuito: introduz um problema de consistência (dados defasados), infraestrutura extra e complexidade de invalidação. Se a consulta já for rápida ou os dados mudarem a cada request, um cache não acrescenta benefício, apenas superfície de falha.
Recomendação: cache-aside (lazy loading)
Com cache-aside, a aplicação verifica primeiro o cache; se o dado não estiver lá (miss), lê do banco, grava no cache e o retorna. É o padrão mais comum e flexível; o cache é preenchido apenas com dados realmente solicitados.
Recomendação: cache read-through
Com read-through, a aplicação conversa apenas com o cache; em caso de miss, a própria camada de cache busca os dados no banco e os popula (por meio de um provider/loader). O código da aplicação fica mais simples e a lógica de preenchimento fica em um só lugar.
Recomendação: cache write-through
Com write-through, toda gravação vai tanto para o cache quanto para o banco (de forma síncrona); ambos são atualizados juntos. Assim, o cache nunca fica atrás do banco e as leituras sempre veem dados atualizados.
Recomendação: cache write-behind (write-back)
Com write-behind, a gravação vai primeiro ao cache e retorna imediatamente ao usuário; a gravação no banco acontece em segundo plano, de forma assíncrona (em lotes/com atraso). A velocidade de gravação é a maior, mas traz riscos de durabilidade e consistência.