← Voltar para o Blog

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-lru

Duas 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íticaComportamento ao encher
noevictionRecusa escrita e devolve erro. É o padrão
allkeys-lruDescarta as chaves menos usadas recentemente
allkeys-lfuDescarta as menos frequentes
volatile-lruDescarta só chaves com TTL definido
volatile-ttlDescarta 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/redis

AOF registra cada operação de escrita. Perda muito menor, arquivo maior e recuperação mais lenta.

appendonly yes
appendfsync everysec

O 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 no

A 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.conf

Outro aviso comum é sobre páginas transparentes, que causam latência irregular:

echo never | sudo tee /sys/kernel/mm/transparent_hugepage/enabled

Para 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-publico

O 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; use SCAN.
  • `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.
  • DEL de chave muito grande — a liberação de memória é síncrona. UNLINK faz 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 RESET

Cada 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-history

Picos 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 keyspace

Chave 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.

Suba um servidor em minutos

Preço em real, suporte em português e dados no Brasil.

Criar conta