Primeiro decida se precisa de cache
Antes de adicionar Redis, meça a consulta, a carga e o objetivo de latência. Cache não corrige automaticamente uma consulta mal indexada, aumenta o número de componentes a operar e pode devolver informação antiga. Também esclareça se Redis será apenas acelerador ou fonte de dados: a estratégia de persistência e recuperação muda conforme o papel.
Cache-aside: o padrão mais simples
Na estratégia cache-aside, a aplicação tenta obter o valor do cache. Se não encontrar, lê a fonte de verdade, armazena uma cópia com expiração e responde. Uma atualização grava primeiro na fonte de verdade e invalida a chave associada; TTL limita por quanto tempo uma chave esquecida pode permanecer.
public async Task<Produto?> ObterAsync(
string id, CancellationToken cancellationToken)
{
var key = $"produto:{id}";
var json = await _cache.StringGetAsync(key);
if (json.HasValue)
return JsonSerializer.Deserialize<Produto>(json!);
var produto = await _repositorio.ObterAsync(id, cancellationToken);
if (produto is not null)
{
var valor = JsonSerializer.Serialize(produto);
await _cache.StringSetAsync(key, valor, TimeSpan.FromMinutes(5));
}
return produto;
}O exemplo é conceitual: trate falhas de serialização, chaves e versões do formato, cancelamento e políticas de falha do cache conforme os requisitos da aplicação. Não mantenha conexão Redis por requisição; use o ciclo de vida recomendado pelo cliente .NET.
Invalidação e consistência
Na atualização, gravar no banco e remover a chave Redis são duas operações separadas. Uma falha entre elas pode deixar uma cópia antiga até o TTL expirar. Para dados sensíveis à consistência, defina explicitamente a tolerância a stale data, invalide após persistir a mudança e considere versão de chave ou outra estratégia quando necessário.
TTL não é apenas limpeza: é parte do contrato de consistência. Tempos menores aumentam misses e carga no banco; tempos maiores prolongam a janela de dados antigos.
Cache stampede, avalanche e chaves quentes
Se uma chave popular expira, muitas requisições simultâneas podem consultar o banco ao mesmo tempo — um cache stampede. Um lock de curta duração, coalescência de requisições, refresh antecipado ou jitter nos TTLs podem ajudar, cada qual com custos e semântica próprios. Evite uma expiração sincronizada de muitas chaves e monitore chaves que concentram tráfego.
Locks distribuídos não são um recurso gratuito nem substituem transações. Use-os apenas com análise de lease, expiração e recuperação após falha, especialmente quando protegem efeitos que não podem se repetir.
O que acontece se Redis ficar indisponível?
Escolha uma política de cache degradado: ignorar cache temporariamente e consultar a fonte, ou falhar a operação quando a fonte não suportar a carga. A escolha depende do produto. Sem limites de timeout e concorrência, um Redis lento pode consumir recursos da aplicação; timeouts, bulkheads e fallback seguro conectam o desenho às práticas de resiliência.
Meça cache hit/miss, latência, erros, memória, evictions, conexões e latência da fonte de dados. Traces ajudam a enxergar se o tempo foi gasto no cache ou no banco: veja observabilidade.
Redis não substitui automaticamente o banco
Cache pode perder chaves, expulsar dados conforme política de memória ou ficar indisponível. Se a informação é fonte de verdade, modele persistência, backups, replicação e recuperação para esse requisito, e não presuma que configuração padrão atende. Também proteja o serviço com autenticação, rede privada, TLS e políticas de acesso adequadas ao ambiente.