Performance e otimização

Gerenciamento eficiente de memória

Estratégias de otimização de memória no Redis — encoding interno, maxmemory, políticas de eviction, fragmentação e monitoramento.

Avançado 30 min 25 pontos Leitura 0%

Nesta aula você vai

  • Compreender encodings internos do Redis e seu impacto na memória
  • Configurar maxmemory e políticas de eviction adequadas ao domínio
  • Detectar e mitigar fragmentação de memória em produção

Gerenciamento eficiente de memória

Objetivos

Nesta aula você vai:

  • Entender como o Redis armazena dados internamente (encodings)
  • Configurar limites de memória e políticas de eviction
  • Detectar fragmentação e aplicar estratégias de mitigação

Conteúdo

A memória como narrativa finita

Todo romance tem limite de páginas; toda instância Redis tem limite de RAM. Diferente de um disco que cresce com demanda, a memória de um servidor é finita e compartilhada. Quando o Redis atinge maxmemory, algo precisa ser sacrificado — e a escolha do que evictar define se o sistema continua saudável ou entra em espiral de cache miss.

Gerenciar memória no Redis é planejar o final da história antes que ela se escreva sozinha.

Anatomia do uso de memória

# Visão geral
redis-cli INFO memory

# Campos essenciais:
# used_memory:          bytes alocados pelo Redis
# used_memory_rss:      bytes que o OS vê (RSS)
# used_memory_peak:     pico histórico
# maxmemory:            limite configurado
# mem_fragmentation_ratio: RSS / used_memory
Métrica Significado saudável Alerta
used_memory / maxmemory < 80% > 90% — eviction iminente
mem_fragmentation_ratio 1,0 – 1,5 > 1,5 — fragmentação; < 1,0 — swap!
used_memory_rss - used_memory Poucos MB Diferença grande → fragmentação

Encodings internos: como o Redis economiza

O Redis escolhe automaticamente a representação mais compacta:

Tipo Encoding Condição Economia
String int Valor numérico inteiro Sem overhead de string
String embstr String ≤ 44 bytes Alocação única
Hash listpack ≤ 128 campos, valores pequenos ~50% vs hash table
List listpack Elementos pequenos Compacto
Set intset Apenas inteiros, ≤ 512 membros Muito compacto
Sorted Set listpack Elementos pequenos Compacto
# Verificar encoding de uma chave
redis-cli OBJECT ENCODING usuario:42
# "listpack" — compacto

redis-cli OBJECT ENCODING usuario:999
# "hashtable" — campos demais ou valores grandes

# Forçar conversão (quando chave cresce além do limite do encoding)
redis-cli HSET usuario:42 campo_extra "valor muito longo que excede o limite do listpack..."
redis-cli OBJECT ENCODING usuario:42
# "hashtable" — agora usa mais memória

Dica de design: mantenha hashes com poucos campos e valores curtos para aproveitar listpack.

Configurando maxmemory

# Definir limite (ex.: 2 GB)
redis-cli CONFIG SET maxmemory 2gb

# Verificar
redis-cli CONFIG GET maxmemory

Regra: defina maxmemory para 70–80% da RAM disponível no servidor, reservando espaço para OS, replicação buffer e AOF rewrite.

Servidor com 8 GB RAM:
  OS + buffers:     1 GB
  Redis maxmemory:  5 GB (reserva 2 GB)
  Pico AOF rewrite: usa reserva

Políticas de eviction

Quando maxmemory é atingido, o Redis remove chaves conforme a política:

Política Comportamento Caso de uso
noeviction Retorna erro em escritas Dados críticos — nunca perder
allkeys-lru Remove chave menos usada (qualquer) Cache puro
allkeys-lfu Remove chave menos frequentemente usada Cache com padrão de acesso estável
volatile-lru Remove chave com TTL menos usada Cache com TTL em todas as chaves
volatile-lfu Remove chave com TTL menos frequente Cache com TTL + padrão estável
volatile-ttl Remove chave com TTL mais próximo de expirar Prioriza retenção de chaves "frescas"
allkeys-random Remove chave aleatória Raro — testes
# Configurar política
redis-cli CONFIG SET maxmemory-policy allkeys-lru

# Verificar estatísticas de eviction
redis-cli INFO stats | grep evicted
# evicted_keys:12345

LFU vs LRU: LFU (Least Frequently Used) é superior quando o padrão de acesso é estável ao longo do tempo — evita que um scan único remova dados frequentemente acessados. LRU é melhor quando o padrão muda frequentemente.

TTL: o eviction programado

A melhor eviction é a que você programa:

# Sempre defina TTL em dados de cache
SET cache:produto:1001 "dados" EX 300

# Verificar TTL restante
TTL cache:produto:1001

# Renovar TTL em acesso (sliding expiration)
EXPIRE cache:produto:1001 300

# Definir TTL em hash existente
EXPIRE usuario:42 3600
Estratégia TTL Eviction policy
Cache de catálogo 5–30 min volatile-lru
Sessão de usuário 24h volatile-lru
Rate limiting 60s volatile-ttl
Dados críticos (lock) Curto + noeviction Nunca evictar

Fragmentação de memória

Quando mem_fragmentation_ratio > 1,5, o Redis usa mais RAM do que os dados efetivamente ocupam:

# Diagnóstico
redis-cli INFO memory | grep fragmentation
# mem_fragmentation_ratio:1.82

# Causas comuns:
# - Updates frequentes em chaves de tamanho variável
# - Deletes massivos seguidos de novas alocações
# - AOF rewrite e BGSAVE (fork COW)

Mitigações:

# 1. Redis 4.0+: ativar defrag ativo
redis-cli CONFIG SET activedefrag yes
redis-cli CONFIG SET active-defrag-threshold-lower 10
redis-cli CONFIG SET active-defrag-threshold-upper 25

# 2. Restart controlado (último recurso)
# Salvar, reiniciar, carregar — memória contígua

# 3. Redis 7.0+: jemalloc tuning
redis-cli CONFIG SET maxmemory-eviction-tenacity 10

Monitoramento proativo

# MEMORY STATS (Redis 4.0+) — breakdown detalhado
redis-cli MEMORY STATS

# Uso de memória por chave
redis-cli MEMORY USAGE usuario:42

# Maiores chaves (amostragem — seguro em produção)
redis-cli --bigkeys

# Análise completa (pode demorar)
redis-cli --memkeys --memkeys-samples 5

Exemplo de saída --bigkeys:

-------- biggest string keys --------
cache:produto:1001 (serialized JSON) - 524288 bytes

-------- biggest hash keys --------
usuario:48291 (47 fields) - 8192 bytes

-------- summary --------
Total keyspace: 2500000 keys
Peak memory: 4.2 GB

Estratégias de redução de memória

Técnica Economia estimada Trade-off
Hash em vez de JSON string 30–50% Menos flexibilidade
Comprimir valores grandes (na app) 50–80% CPU de compressão
Reduzir tamanho de chaves 5–15% Legibilidade
TTL agressivo Variável Mais cache miss
Particionar em múltiplas instâncias N/A Complexidade operacional
# Chaves curtas economizam memória em escala
# Ruim:  cache:product:category:electronics:item:1001
# Bom:   c:p:el:1001

# Comparação de overhead
redis-cli MEMORY USAGE "cache:product:category:electronics:item:1001"
redis-cli MEMORY USAGE "c:p:el:1001"

Alertas recomendados (Prometheus)

# Memória acima de 85% do maxmemory
redis_memory_used_bytes / redis_memory_max_bytes > 0.85

# Fragmentação alta
redis_mem_fragmentation_ratio > 1.5

# Eviction ativa (chaves sendo removidas)
rate(redis_evicted_keys_total[5m]) > 0

Resumo

  • Redis usa encodings compactos (listpack, intset) — design de chaves influencia memória
  • Configure maxmemory (70–80% da RAM) e política de eviction alinhada ao domínio
  • Monitore mem_fragmentation_ratio e ative activedefrag quando > 1,5
  • TTL em todas as chaves de cache é a melhor política de eviction

Para refletir

Execute redis-cli --bigkeys no seu ambiente. Qual tipo de chave consome mais memória? A estrutura de dados é a ideal para o padrão de acesso?