Dominando a Arquitetura de Redis
Redis não é “só cache”. Ele vira uma camada de arquitetura quando você entende persistência, consistência, modelagem de dados, cluster e observabilidade. Aqui eu organizo o raciocínio para você projetar sistemas confiáveis e performáticos.
1) Modelo mental: dados, semântica e SLA
A primeira decisão arquitetural é definir o que Redis representa no seu sistema. Não adianta otimizar comandos se você não sabe se o dado é: cache reconstituível, estado temporário (por exemplo, rate limit) ou fonte de verdade.
- Cache reconstituível: perda eventual é aceitável; o TTL é seu “contrato”. Você modela para tolerar falhas e evitar thundering herd.
- Estado temporário: você precisa de baixa latência e previsibilidade, mas não necessariamente de retenção longa. Aqui, TTL e comandos atômicos importam.
- Fonte de verdade: você precisa lidar com persistência, replicação e estratégia de failover. Redis precisa de arquitetura completa (e não apenas “instalar e pronto”).
2) Persistência e replicação: escolha com intenção
Redis oferece persistência e replicação para reduzir risco. O objetivo não é “habilitar tudo”, e sim adequar o comportamento às suas necessidades.
- RDB (snapshots): bom para recuperação a partir de pontos no tempo. Impacto de escrita pode ocorrer no processo de snapshot dependendo da carga.
- AOF (append-only file): registra comandos para reconstrução. Permite escolhas de durabilidade com trade-offs (fsync).
- Replicação (master/replica): melhora disponibilidade e cria base para failover.
- Cluster: escala horizontal por partição (sharding), e adiciona complexidade operacional.
Se você precisa garantir consistência forte, pense além de persistência: como o cliente se comporta durante failover, como você evita writes duplicados e quais invariantes seu domínio exige.
3) Modelagem de dados: estruturas corretas evitam “gambiarras”
Arquitetura de Redis começa na modelagem. O mesmo “dado” pode ser representado de formas bem diferentes, com impacto direto em latência, memória e concorrência.
- Strings: simples para valores escalares e números. Use com TTL quando for cache/controle de tempo.
-
Hashes: quando você precisa atualizar campos individualmente (ex.: perfil).
Evita regravar grandes blobs via
SET. - Listas / Streams: quando a ordem e o consumo fazem parte do fluxo. Streams oferecem semântica de processamento e idempotência por offset.
- Set / Sorted Set: para deduplicação e rankings. Sorted Set é o que mais aparece em “timeline” e ordenação por score.
- Bitmaps / HyperLogLog: úteis para cardinalidade aproximada e filtros compactos. Excelente quando a métrica não precisa ser exata.
4) Cluster, chaves e consistência operacional
Conforme o volume cresce, você tende a sharding. No mundo Redis Cluster, a arquitetura passa a depender de como as chaves se distribuem.
- Chaveamento com Hash Tags: agrupar chaves relacionadas na mesma partição reduz problemas de operações multi-chave.
- Operações multi-key: no Cluster, elas podem exigir roteamento/coordenação — planeje para não “matar” latência.
- Estratégia de leitura/escrita: defina onde escreve, se lê de réplica, e qual tolerância a consistência você aceita.
- Failover: protocolo e comportamento do cliente precisam estar alinhados. Se o cliente assume que “sempre vai funcionar”, você perde disponibilidade na prática.
Padrão prático: lock distribuído com TTL e atomicidade
Um lock distribuído bem implementado reduz duplicidade de trabalho quando múltiplos workers disputam a mesma tarefa.
A ideia é simples: adquirir o lock com SET usando NX (não sobrescrever)
e EX (TTL para evitar deadlock).
-- Tente adquirir lock
-- key: lock:processo:<id>
-- ttl: em segundos
SET lock:processo:123 NX EX 15
-- Se retornou "OK", você tem o lock
-- Faça o trabalho protegido...
-- Ao final, libere o lock de forma segura
-- (você precisa comparar um token exclusivo)
-- Exemplo em aplicação:
-- token = <valor aleatório único>
-- No Redis:
-- SET lock:processo:123 token NX EX 15
-- ... trabalho ...
-- DEL só se token bater (melhor com script para atomicidade)
Se você precisa de liberação segura (DEL apenas se o lock ainda for seu), use um fluxo atômico no servidor: compare o token antes de remover. Isso evita um cenário clássico onde seu lock expirou e outro worker pegou o mesmo lock — e você acabou liberando algo que não era mais seu.
Agora que você organizou a arquitetura, bora aprofundar?
Se você quer ir além no mesmo nível técnico (modelagem, padrões de uso e operação), recomendo continuar com outros posts do yurideveloper.com e aplicar no seu cenário real.