Redis: cache, sessão, fila e outros casos de uso
Para que serve Redis na prática: cache com TTL e eviction, session store, rate limiting, filas, pub/sub e locks distribuídos, e por que ele não é seu banco.
Toda aplicação que cresce chega no mesmo ponto: uma query que era instantânea no começo agora leva 400ms porque a tabela tem milhões de linhas e o JOIN não perdoa. Você indexa, otimiza, e ainda assim o banco vira o gargalo nos picos. Em algum momento alguém diz "bota um Redis na frente" — e funciona. Mas Redis não serve só pra cache: gente usa pra sessão, pra rate limiting, pra fila improvisada, pra ranking de jogo, pra lock distribuído. O problema é que cada um desses usos tem armadilhas, e a frase "está em memória, eu posso perder dado?" merece uma resposta honesta antes de você confiar dado importante nele.
Este texto cobre os usos reais do Redis, quando cada um faz sentido e onde o canivete suíço corta a mão de quem o usa.
O que é Redis, na prática
Redis é um key-value store que vive na RAM. É rápido por causa disso: não tem disco no caminho crítico, não tem parser de SQL, não tem planner de query. Você pede uma key, ele devolve o valor. As estruturas vão além de string simples — tem hash, list, set, sorted set, e cada uma existe porque resolve um problema específico.
Ele é single-threaded para comandos, o que assusta quem vem de banco relacional. Na prática isso é uma vantagem: não há lock contention, não há race condition entre comandos, cada operação é atômica por definição. Um único core moderno aguenta dezenas de milhares de operações por segundo porque cada comando dura microssegundos. O gargalo costuma ser a rede e o tamanho do payload, não a CPU do Redis.
Cache: o uso que justifica a instalação
O padrão mais comum é o cache-aside. A aplicação pergunta ao Redis primeiro; se a key existe (cache hit), usa o valor; se não existe (cache miss), busca no banco, grava no Redis com um TTL e devolve.
GET user:42:profile
SET user:42:profile "{...}" EX 300
O EX 300 define um TTL de 300 segundos. Passou disso, a key expira sozinha e o próximo acesso recarrega do banco. TTL é o que impede o cache de servir dado velho para sempre — sem ele, você vira refém de invalidação manual, que é a fonte de metade dos bugs de cache da história.
Quando a memória enche, entra a eviction policy. A default noeviction faz o Redis recusar escritas novas — péssimo para cache. Para cache você quer allkeys-lru, que descarta as keys menos usadas recentemente. Existe também allkeys-lfu (menos frequentes), útil quando o padrão de acesso é estável. Configure isso explicitamente; o default vai te morder num pico de tráfego.
Uma observação de quem já apanhou: cache não é onde você guarda a única cópia de nada. Se a key sumir por eviction ou por um restart, o sistema tem que sobreviver buscando no banco. Cache acelera; não é fonte de verdade.
Session store
Guardar sessão de usuário no Redis é quase obrigatório quando você tem mais de um servidor de aplicação. Sem isso, a sessão fica presa na memória de um processo e o load balancer manda o usuário para outra máquina que não o conhece — ou você gruda o usuário num servidor (sticky sessions) e perde a flexibilidade.
A sessão tem TTL natural: expira por inatividade. Você armazena num hash e renova a expiração a cada request.
HSET sess:abc123 user_id 42 role admin
EXPIRE sess:abc123 1800
Aqui a tolerância à perda é diferente do cache. Perder uma sessão significa deslogar o usuário — chato, mas não catastrófico. Ainda assim, é o tipo de dado em que você começa a se perguntar sobre persistência, e já chego nisso.
Rate limiting
Limitar requisições por usuário ou por IP é um caso onde a atomicidade do Redis brilha. O padrão clássico é INCR mais EXPIRE:
INCR rate:ip:203.0.113.5
EXPIRE rate:ip:203.0.113.5 60
A primeira requisição cria a key em 1 e marca expiração de 60 segundos. As próximas incrementam. Quando o contador passa do limite, você bloqueia até a key expirar e zerar a janela. Como o INCR é atômico, não há risco de duas requisições simultâneas lerem o mesmo valor e incrementarem errado — problema que você teria de resolver com lock num banco relacional. Para janelas mais sofisticadas (sliding window) usa-se sorted set, mas o INCR cobre 90% dos casos.
Filas: até onde Redis vai
Dá pra fazer fila com lists. LPUSH insere de um lado, BRPOP consome do outro de forma bloqueante:
LPUSH jobs:email "{to: 'x@y.com'}"
BRPOP jobs:email 0
O BRPOP fica esperando até aparecer item, sem polling. Para uma fila simples de jobs internos, isso resolve e é barato. O Redis Streams melhora isso com consumer groups e acknowledgment.
Agora a parte honesta: para fila séria, um broker de verdade ganha do Redis. RabbitMQ, SQS ou Kafka entregam o que o Redis não dá de graça — garantia de entrega, dead-letter queue, retry com backoff, persistência robusta de mensagens, roteamento. Com lists, se o worker pega a mensagem e morre antes de processar, a mensagem se perdeu. Dá pra mitigar com RPOPLPUSH para uma fila de processamento, mas você está reimplementando, mal, o que um broker já faz bem. Use Redis para fila quando a fila é simples e a perda eventual de um job é aceitável. Para pagamento, não.
Pub/sub, leaderboards e locks distribuídos
Pub/sub do Redis é fire-and-forget: o publisher manda numa channel, os subscribers ativos recebem. Quem não estava conectado na hora perde a mensagem — não confunda com fila. Bom para notificação em tempo real, invalidação de cache entre nodes, sinais efêmeros.
Leaderboard é o caso de uso perfeito para sorted set. ZADD insere com score, ZREVRANGE devolve o top N já ordenado, e ZRANK dá a posição de um membro — tudo em tempo logarítmico. Ranking de jogo, top produtos, trending: é quase desonesto de tão conveniente.
Lock distribuído é onde mora o perigo. A versão ingênua — SET lock:x token NX EX 10 para adquirir e DEL para soltar — parece certa e quebra em casos sutis: o processo que adquiriu pode pausar (GC, swap), o lock expira, outro processo pega o lock, e o primeiro acorda e dá DEL no lock que agora pertence a outro. A solução correta usa um token único e libera o lock com um script Lua que verifica o token antes do DEL. Para múltiplos nodes Redis existe o algoritmo Redlock, que tem seus críticos. Conselho: se você precisa de lock distribuído confiável, leia bastante antes de escrever; a versão ingênua que parece funcionar é a que te acorda às 3 da manhã.
Persistência: posso perder dado?
A pergunta certa. Redis vive na RAM, mas tem dois mecanismos de persistência. O RDB tira snapshots periódicos do dataset em disco — rápido para restaurar, mas você perde tudo que mudou desde o último snapshot se cair no meio. O AOF (append-only file) grava cada operação de escrita num log; perde menos, mas o arquivo cresce e a restauração é mais lenta. Dá pra combinar os dois.
Mesmo com AOF no modo mais seguro, Redis não é um banco transacional com durabilidade ACID na mesma liga de um Postgres. Por isso a regra: não guarde a única cópia de dado importante no Redis. Cache, sessão, contador, ranking — coisas que você pode reconstruir ou cuja perda é tolerada. A fonte de verdade fica no banco principal. Se você está na dúvida entre um banco relacional e uma opção NoSQL para essa fonte de verdade, o tema rende — veja banco relacional vs NoSQL para o contexto de escolha.
Um detalhe prático de quem opera Redis: ao depurar expiração e TTL você vai ler timestamps Unix em logs e em comandos como EXPIRETIME, que devolve o instante de expiração em epoch. Converter aquele número cru para uma data legível ajuda a entender se a key vai expirar quando você acha — dá pra fazer rápido com o conversor de timestamp.
Perguntas frequentes
Para que serve o Redis?
Redis serve para guardar dados em memória com acesso muito rápido, em casos onde latência importa mais do que durabilidade absoluta. Os usos mais comuns são cache (acelerar leituras que normalmente bateriam no banco), session store, rate limiting, contadores, leaderboards com sorted sets, pub/sub e filas simples. É um canivete suíço de infraestrutura, mas não um substituto do banco principal.
Redis pode ser usado como banco de dados principal?
Tecnicamente dá, mas raramente é uma boa ideia. Ele tem persistência (RDB e AOF), porém o modelo de durabilidade não se compara ao de um banco transacional, e o custo de manter tudo em RAM cresce rápido. A prática saudável é usar Redis como camada de aceleração e armazenamento efêmero, mantendo a fonte de verdade num banco que aguenta queda sem perder o último segundo de escritas.
Qual a diferença entre Redis e Memcached?
Memcached é um cache de chave-valor puro, mais simples e ótimo se você só quer cachear strings. Redis faz isso e muito mais: estruturas ricas (hash, list, set, sorted set), persistência opcional, pub/sub, scripting Lua e replicação. Se a sua necessidade é estritamente cache de string e nada além, Memcached basta; na dúvida, Redis cobre mais terreno.
Redis é single-threaded mesmo? Isso não é lento?
É single-threaded para a execução de comandos, e isso não é lento porque cada comando dura microssegundos e roda inteiramente na memória. A ausência de concorrência entre comandos elimina locks e race conditions e torna toda operação atômica. Versões recentes usam threads para I/O de rede, mas a lógica de comandos permanece serial — de propósito.
Resumo prático
Redis é a melhor coisa que você pode colocar entre a aplicação e o banco quando a latência começa a doer. Para cache use cache-aside com TTL e configure allkeys-lru em vez de confiar no default. Sessão, rate limiting com INCR+EXPIRE, leaderboards com sorted set e pub/sub são usos onde ele é quase imbatível. Fila com list resolve o caso simples, mas para fila séria pegue um broker de verdade. Lock distribuído, faça com cuidado e token único, nunca a versão ingênua. E acima de tudo: configure persistência conscientemente e nunca guarde a única cópia de dado importante na RAM. Redis acelera tudo; ser fonte de verdade não é o trabalho dele.
- 01 O que é software open source Open source não significa gratuito. Entenda o que a licença realmente define, as diferenças entre MIT, GPL e Apache, e como projetos open source se sustentam financeiramente.
- 02 PostgreSQL vs MySQL: diferenças práticas para quem precisa escolher Comparativo honesto entre PostgreSQL e MySQL: tipos nativos, JSONB vs JSON_EXTRACT, concorrência MVCC e extensões. Por que PostgreSQL como default faz sentido.