Redis: memória, despejo e persistência sem surpresa
O Redis é rápido e silencioso até o dia em que enche a memória. O que acontece então depende de uma configuração que quase ninguém define — e o padrão não é o que você espera.
Equipe EasyOps Cloud · · 7 min de leitura
O Redis é a peça mais silenciosa da infraestrutura. Ele sobe, responde em microssegundos e não dá trabalho — até o dia em que a memória acaba.
O que acontece nesse momento depende de uma configuração que a maioria das
instalações nunca definiu. E o comportamento padrão surpreende: sem maxmemory, o
Redis cresce até consumir toda a RAM da máquina, e então o kernel escolhe um
processo para matar. Frequentemente o próprio Redis, levando junto tudo que
estava em memória.
Definir o teto, sempre
# /etc/redis/redis.conf
maxmemory 1gb
maxmemory-policy allkeys-lruDuas linhas que mudam o comportamento sob pressão de "derrubar a máquina" para "descartar o que é menos usado".
O valor deve deixar folga. O Redis usa memória além dos dados: buffers de
replicação, buffers de cliente e a cópia temporária durante o salvamento em
disco. Reservar 60% a 70% da RAM disponível para maxmemory é o ponto de partida
seguro.
Confirme o consumo real e a fragmentação:
redis-cli INFO memory | grep -E 'used_memory_human|maxmemory_human|mem_fragmentation_ratio'O mem_fragmentation_ratio acima de 1,5 indica fragmentação relevante — o
processo segura mais memória do sistema do que os dados ocupam. Costuma se
resolver com reinício, e pode ser mitigado com desfragmentação ativa em versões
recentes.
A política de despejo muda tudo
Este é o parâmetro que separa um cache saudável de uma perda de dados silenciosa:
| Política | Comportamento ao encher |
|---|---|
| noeviction | Recusa escrita e devolve erro. É o padrão |
| allkeys-lru | Descarta as chaves menos usadas recentemente |
| allkeys-lfu | Descarta as menos frequentes |
| volatile-lru | Descarta só chaves com TTL definido |
| volatile-ttl | Descarta as que expiram antes |
A escolha depende do papel do Redis, e é aqui que mora o erro mais comum.
Como cache puro, allkeys-lru é a resposta. Perder uma chave significa apenas
recalcular — o custo é uma consulta a mais, não um dado perdido.
Como armazenamento de dado que importa — fila de trabalho, sessão de usuário —, noeviction
é o correto. É melhor a escrita falhar de forma explícita, e alguém descobrir,
do que o Redis descartar em silêncio a tarefa que precisava ser processada.
Misturando os dois, volatile-lru limita o descarte às chaves que têm prazo de
validade. Isso exige disciplina: todo dado descartável precisa de TTL, e todo
dado importante precisa não ter.
Vale ser direto sobre o risco de misturar cache e fila na mesma instância. Sob pressão de memória, uma política de despejo agressiva pode apagar itens da fila, e o sintoma é o pior possível — trabalho que desaparece sem erro em lugar nenhum. Duas instâncias separadas, com configurações diferentes, custam pouco e eliminam a categoria.
Persistência: RDB, AOF ou nenhum
O Redis grava em memória e oferece dois mecanismos de persistência, com trocas diferentes.
RDB é um retrato periódico do conjunto inteiro. Arquivo compacto, recuperação rápida, e a perda potencial é tudo o que aconteceu desde o último retrato.
save 900 1
save 300 10
save 60 10000
dbfilename dump.rdb
dir /var/lib/redisAOF registra cada operação de escrita. Perda muito menor, arquivo maior e recuperação mais lenta.
appendonly yes
appendfsync everysecO everysec é o meio-termo sensato: sincroniza a cada segundo, e a perda máxima é
de um segundo de escrita. O always sincroniza a cada operação e custa desempenho
de forma perceptível; o no deixa a decisão para o sistema operacional e pode
perder bem mais.
Nenhum dos dois é uma escolha legítima quando o Redis é só cache. Desligar a persistência elimina os picos de latência do salvamento e acelera a partida. Perder tudo em um reinício é aceitável quando tudo é recalculável.
save ""
appendonly noA decisão decorre da pergunta anterior: se perder o conteúdo é irrelevante, não persista; se é relevante, o Redis provavelmente não deveria ser a única cópia.
O aviso que quase ninguém lê
Ao subir com persistência ativa, o Redis costuma registrar um alerta sobre overcommit_memory.
Ele não é decorativo.
O salvamento em disco duplica o processo. Se o kernel estiver configurado para recusar reservas maiores que a memória livre, o salvamento falha — e falha justamente quando o Redis está mais cheio.
sudo sysctl vm.overcommit_memory=1
echo 'vm.overcommit_memory=1' | sudo tee /etc/sysctl.d/99-redis.confOutro aviso comum é sobre páginas transparentes, que causam latência irregular:
echo never | sudo tee /sys/kernel/mm/transparent_hugepage/enabledPara tornar permanente, o caminho é uma unit do systemd que aplique isso no boot — o mesmo padrão descrito no artigo sobre escrever units.
Segurança: o padrão é aberto
O Redis não tem autenticação por padrão e, em instalação antiga, pode escutar em todas as interfaces. Um Redis exposto à internet é comprometido em horas — é um dos alvos preferidos de varredura automatizada, porque permite escrita de arquivo arbitrário em muitas configurações.
bind 127.0.0.1 ::1
protected-mode yes
requirepass uma-senha-longa-e-aleatoria
# Desabilitar comandos perigosos
rename-command FLUSHALL ""
rename-command CONFIG ""Confirme de fora, e não da própria máquina:
nmap -Pn -p 6379 seu-ip-publicoO resultado precisa ser filtered. Se vier open, revise a regra de firewall — e
lembre que container publicando -p 6379:6379 fura o ufw, situação detalhada no
artigo sobre firewall na VM e na nuvem.
O comando único que trava tudo
O Redis executa um comando por vez. Isso é o que garante a consistência das operações e é também a sua maior armadilha operacional: qualquer comando lento bloqueia todos os clientes enquanto roda.
Alguns comandos comuns têm custo proporcional ao tamanho do conjunto, e em produção com milhões de chaves isso significa segundos de indisponibilidade:
KEYS— varre o espaço inteiro. Nunca em produção; useSCAN.- `FLUSHALL` e `FLUSHDB` sem
ASYNC— liberam tudo de forma síncrona. - `SMEMBERS`, `HGETALL`, `LRANGE 0 -1` em coleção enorme — trazem tudo de uma vez.
DELde chave muito grande — a liberação de memória é síncrona.UNLINKfaz o mesmo em segundo plano.
Para descobrir se isso já acontece, o Redis tem um registro próprio de comandos lentos:
redis-cli CONFIG SET slowlog-log-slower-than 10000 # microssegundos
redis-cli SLOWLOG GET 10
redis-cli SLOWLOG RESETCada entrada traz o comando, os argumentos e a duração. Encontrar um KEYS ali
explica de imediato aquelas travadas de dois segundos que ninguém conseguia
correlacionar com nada.
Vale acompanhar também a latência percebida, que captura inclusive as pausas causadas pelo salvamento em disco:
redis-cli --latency-historyPicos periódicos coincidindo com o intervalo de save são a assinatura do
salvamento RDB — e o motivo para reavaliar se a persistência é mesmo necessária
naquela instância.
Descobrir o que ocupa a memória
Quando o consumo cresce sem explicação, três comandos respondem:
# Distribuição por tipo e tamanho, sem travar o servidor
redis-cli --bigkeys
# Amostragem de memória por chave
redis-cli --memkeys
# Quantas chaves não têm prazo de validade
redis-cli INFO keyspaceChave sem TTL é a causa mais comum de crescimento indefinido. Vale conferir por
padrão de nome:
redis-cli --scan --pattern 'sessao:*' | head -20 | \
xargs -I{} redis-cli TTL {}Resultado -1 significa que a chave nunca expira. Em dado de cache, isso quase
sempre é esquecimento — e o acúmulo delas é o que leva ao despejo, que por sua
vez é o que apaga o que não devia.
Nunca use KEYS * em produção: ele bloqueia o servidor inteiro enquanto varre. O --scan
percorre em lotes e não trava.
O checklist
- `maxmemory` definido, com folga para os buffers.
- Política de despejo escolhida conforme o papel — e cache separado de fila.
- Persistência coerente com o valor do dado.
- `bind` e senha configurados, porta fechada para fora.
- `TTL` em tudo que é descartável.
- Monitorar `evicted_keys`, que é o sinal de que o teto está apertado:
redis-cli INFO stats | grep -E 'evicted_keys|keyspace_misses'Despejo crescente com taxa de acerto caindo significa que o cache deixou de funcionar como cache — está descartando mais rápido do que aproveita. A resposta é mais memória, ou menos dado guardado, e o dimensionamento da máquina resolve o primeiro caso com upgrade em janela curta.
Uma observação final sobre o papel do Redis na arquitetura. Ele é excelente como camada de aceleração e como estrutura auxiliar — contador, fila simples, trava distribuída, sessão. Ele não é um banco de dados primário, e tratá-lo como tal é a origem da maioria dos incidentes graves envolvendo perda.
O critério prático: se perder todo o conteúdo do Redis significar perder informação que não existe em nenhum outro lugar, a arquitetura precisa mudar — não a configuração de persistência. Persistência reduz a janela de perda; ela não transforma um cache em fonte da verdade.