Produção, Tuning e Segurança
Aula 6 de 6
Persistence
RDB (Snapshot)
# redis.conf — RDB
save 900 1 # snapshot a cada 15 min se >= 1 chave alterada
save 300 10 # snapshot a cada 5 min se >= 10 chaves
save 60 10000 # snapshot a cada 1 min se >= 10000 chaves
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
rdb-del-sync-files no
dbfilename dump.rdb
dir /var/lib/redis
# Comandos manuais
BGSAVE # snapshot em background
SAVE # snapshot bloqueante (não usar em produção)
LASTSAVE # timestamp do último snapshot
AOF (Append Only File)
# redis.conf — AOF
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec # fsync a cada 1s (equilíbrio)
# Opções de fsync:
# always: fsync a cada comando (mais seguro, mais lento)
# everysec: fsync a cada 1s (recomendado)
# no: deixa para o SO (mais rápido, menos seguro)
# Rewrite (compactação)
auto-aof-rewrite-percentage 100 # rewrite quando AOF dobra de tamanho
auto-aof-rewrite-min-size 64mb # mínimo para fazer rewrite
# Comando manual
BGREWRITEAOF
# Segurança ao carregar AOF
aof-load-truncated yes # carregar AOF truncado (último comando incompleto)
aof-use-rdb-preamble yes # RDB + AOF hybrid (Redis 7.4+)
RDB + AOF Hybrid (Redis 7.4+)
# Redis 7.4+ combina RDB e AOF
aof-use-rdb-preamble yes
# Durante BGREWRITEAOF, Redis cria:
# 1. Um snapshot RDB (dados até o momento)
# 2. Comandos incrementais em AOF
# Vantagens:
# - Carregamento mais rápido que AOF puro
# - Menor perda de dados que RDB puro
# - Tamanho menor que AOF puro
# ⚠️ IMPORTANTE: Redis 7.4 introduziu:
# - aof-use-rdb-preamble como padrão yes
# - AOF sempre carrega RDB primeiro, depois aplica AOF
Sentinel
Configuração
# /etc/redis/sentinel.conf
port 26379
daemonize no
pidfile /var/run/redis-sentinel.pid
logfile /var/log/redis/sentinel.log
# Monitorar o master
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
# Autenticação
sentinel auth-pass mymaster SuaSenhaAqui
# Notificações
sentinel notification-script mymaster /etc/redis/notify.sh
Três instâncias Sentinel
# Executar 3 sentinels (mínimo para quorum)
redis-sentinel /etc/redis/sentinel-1.conf
redis-sentinel /etc/redis/sentinel-2.conf
redis-sentinel /etc/redis/sentinel-3.conf
# Verificar status
redis-cli -p 26379 SENTINEL masters
redis-cli -p 26379 SENTINEL slaves mymaster
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster
redis-cli -p 26379 SENTINEL ckquorum mymaster # verificar quorum
# Simular failover
redis-cli -p 26379 SENTINEL failover mymaster
Client Awareness (Redis 7.2+)
# Clientes modernos podem descobrir o master via sentinel
# Exemplo Node.js (ioredis):
# const Redis = require('ioredis');
# const redis = new Redis({
# sentinels: [
# { host: 'sentinel1', port: 26379 },
# { host: 'sentinel2', port: 26379 },
# { host: 'sentinel3', port: 26379 }
# ],
# name: 'mymaster'
# });
Cluster
Configuração
# redis.conf — Cluster (mínimo 3 masters, 3 réplicas)
port 7000
cluster-enabled yes
cluster-config-file nodes-7000.conf
cluster-node-timeout 5000
appendonly yes
Criar Cluster
# Iniciar 6 instâncias
redis-server redis-7000.conf
redis-server redis-7001.conf
redis-server redis-7002.conf
redis-server redis-7003.conf
redis-server redis-7004.conf
redis-server redis-7005.conf
# Criar cluster (3 masters + 3 réplicas)
redis-cli --cluster create \
127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 \
127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 \
--cluster-replicas 1
# Hash slots: 0-16383 distribuídos entre os 3 masters
# Cada master tem 5461-5462 slots
Operações no Cluster
# Informações
redis-cli -p 7000 CLUSTER INFO
redis-cli -p 7000 CLUSTER NODES
redis-cli -p 7000 CLUSTER SLOTS
# Contar keys por nó
redis-cli -p 7000 CLUSTER COUNTKEYSINSLOT 0 # keys em slot específico
redis-cli -p 7000 DBSIZE
# Adicionar nó
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000
# Adicionar como réplica
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000 --cluster-slave
# Remover nó
redis-cli --cluster del-node 127.0.0.1:7006 <node-id>
# Rebalancear slots
redis-cli --cluster rebalance 127.0.0.1:7000
Resharding
# Mover slots de um nó para outro
redis-cli --cluster reshard 127.0.0.1:7000
# Modo não interativo:
# Mover 1000 slots do nó source para o nó target
redis-cli --cluster reshard 127.0.0.1:7000 \
--cluster-from <source-node-id> \
--cluster-to <target-node-id> \
--cluster-slots 1000 \
--cluster-yes
# Verificar distribuição
redis-cli --cluster check 127.0.0.1:7000
Movimentação de Dados
# Quando um cliente acessa um nó que não tem o slot:
# MOVED: redirecionamento permanente (hash slot movido)
# ASK: redirecionamento temporário (resharding em andamento)
# Cliente recebe:
# -MOVED 1234 127.0.0.1:7001
# Deve reenviar para o nó correto e atualizar rota
# -ASK 1234 127.0.0.1:7001
# Deve enviar ASKING antes do comando, depois reenviar
Monitoring
# INFO — visão geral
redis-cli INFO
# Seções específicas
redis-cli INFO server
redis-cli INFO clients
redis-cli INFO memory
redis-cli INFO persistence
redis-cli INFO stats
redis-cli INFO replication
redis-cli INFO cluster
redis-cli INFO keyspace
# Métricas importantes no INFO:
# instantaneous_ops_per_sec: comandos/s atuais
# instantaneous_input_kbps: entrada KB/s
# instantaneous_output_kbps: saída KB/s
# hit_rate: keyspace_hits / (keyspace_hits + keyspace_misses)
# connected_clients
# blocked_clients
# used_memory_rss / used_memory (fragmentation)
SLOWLOG
# Comandos lentos
CONFIG SET slowlog-log-slower-than 10000 # 10ms (microssegundos)
CONFIG SET slowlog-max-len 1000
# Ver log
SLOWLOG GET
SLOWLOG GET 5 # últimos 5 comandos lentos
SLOWLOG LEN # total de entradas
SLOWLOG RESET # limpar log
# Exemplo de saída:
# 1) 1) (integer) 123 # ID
# 2) (integer) 1717000 # timestamp
# 3) (integer) 25000 # duração (microssegundos)
# 4) 1) "KEYS" # comando
# 2) "*"
# 5) "127.0.0.1:6379" # cliente
MONITOR (Apenas Debug)
# ⚠️ MONITOR: APENAS PARA DEBUG!
# Reduz performance em ~50%, NÃO usar em produção
redis-cli MONITOR
# 1717000000.123456 [0 127.0.0.1:6379] "SET" "key" "value"
# 1717000000.123457 [0 127.0.0.1:6379] "GET" "key"
# Alternativa segura: INFO stats + SLOWLOG
redis-benchmark e Latency
# Benchmark básico
redis-benchmark -q -n 100000 -c 50
# -q: quiet (apenas resumo)
# -n 100000: 100k requisições
# -c 50: 50 conexões paralelas
# Testar comandos específicos
redis-benchmark -t SET,GET,Lpush -q
# Testar pipeline
redis-benchmark -P 16 -q
# Latency Doctor (Redis 7.2+)
redis-cli --latency # latência contínua
redis-cli --latency-history # histórico a cada 15s
redis-cli --latency-dist # distribuição (gráfico)
redis-cli --intrinsic-latency 100 # latência intrínseca do sistema
Security
ACL — Access Control Lists (Redis 6+)
# Listar usuários
ACL LIST
# user default on nopass ~* +@all
# Criar usuário
ACL SETUSER app_user on >senha123 ~* +@all -@dangerous
# Usuário com permissões específicas
ACL SETUSER read_only on >read123 ~* +@read +@pubsub
# Usuário restrito a keys específicas
ACL SETUSER cache_user on >cache123 ~cache:* +@read +@write
# Categorias de comandos
# @read: GET, MGET, HGET, etc.
# @write: SET, DEL, EXPIRE, etc.
# @admin: CONFIG, SHUTDOWN, DEBUG, etc.
# @dangerous: FLUSHALL, DEBUG, CONFIG SET, etc.
# @fast: comandos O(1)
# @slow: comandos O(N) como KEYS
# @pubsub: PUBLISH, SUBSCRIBE, etc.
# @connection: AUTH, PING, QUIT, etc.
# Usuário sem comandos perigosos
ACL SETUSER app_user2 on >appP@ss ~app:* +@all -@admin -@dangerous
# Gerar ACL file
ACL SAVE
# ACL log
ACL LOG
ACL LOG RESET
# Verificar permissões
ACL GETUSER app_user
SSL/TLS
# redis.conf — TLS
tls-port 6380
port 0 # desabilitar porta não-TLS
tls-cert-file /etc/redis/certs/redis.crt
tls-key-file /etc/redis/certs/redis.key
tls-ca-cert-file /etc/redis/certs/ca.crt
tls-auth-clients yes
tls-protocols "TLSv1.2 TLSv1.3"
tls-ciphers "EECDH+AESGCM:EDH+AESGCM"
tls-prefer-server-ciphers yes
# Conectar com TLS
redis-cli --tls \
--cert /etc/redis/certs/client.crt \
--key /etc/redis/certs/client.key \
--cacert /etc/redis/certs/ca.crt
Comandos Perigosos — Rename
# redis.conf — desabilitar/renomear comandos perigosos
rename-command FLUSHALL ""
rename-command FLUSHDB ""
rename-command CONFIG ""
rename-command SHUTDOWN ""
rename-command DEBUG ""
rename-command SCRIPT ""
# Ou renomear para dificultar:
rename-command FLUSHALL "5f4dcc3b5aa765d61d8327deb882cf99"
rename-command DEBUG "ea6a78593e3c7b44d75ec9b12c23b7f3"
Memory Optimization
# Ver fragmentação
redis-cli INFO memory | grep mem_fragmentation_ratio
# > 1.5: fragmentação alta (pode precisar restart ou MEMORY PURGE)
# < 1.0: swapping (perigoso!)
# Ver memória usada por chave
redis-cli MEMORY USAGE key_name
redis-cli MEMORY STATS
redis-cli MEMORY DOCTOR # diagnóstico e recomendações
# Otimizações
# 1. Usar Hash ao invés de String para objetos
# user:1001:name + user:1001:email → HSET user:1001 name "Maria" email...
# Economia: ~50% para objetos com 5+ campos
# 2. Usar inteiros ao invés de strings
# SET age 30 ao invés de SET age "30"
# 3. Usar TTL para dados temporários
# SET temp:data "..." EX 300
# 4. Escolher encoding apropriado
# list-max-ziplist-size -2 # -2 = 8KB max per node
# hash-max-listpack-entries 512
# hash-max-listpack-value 64
# set-max-intset-entries 512
# zset-max-listpack-entries 128
# zset-max-listpack-value 64
Kernel Tuning
# /etc/sysctl.conf — ajustes para Redis em produção
# Overcommit memory (essencial para BGSAVE)
vm.overcommit_memory = 1
# Desabilitar Transparent Huge Pages (THP)
echo never > /sys/kernel/mm/transparent_hugepage/enabled
# Networking
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
vm.swappiness = 1 # evitar swap
# Aplicar
sysctl -p
# THP systemd service (persistente)
# Criar /etc/systemd/system/disable-thp.service
# [Unit]
# Description=Disable Transparent Huge Pages
#
# [Service]
# Type=oneshot
# ExecStart=/bin/sh -c "echo never > /sys/kernel/mm/transparent_hugepage/enabled"
# RemainAfterExit=yes
#
# [Install]
# WantedBy=multi-user.target
Lab: Cluster Redis em Docker Compose
cat > docker-compose.yml << 'YAML'
version: '3.8'
services:
redis-master-1:
image: redis:7-alpine
ports: ["7001:6379"]
volumes: ["./conf/redis-1.conf:/usr/local/etc/redis/redis.conf"]
command: redis-server /usr/local/etc/redis/redis.conf
networks: [redis-cluster]
redis-master-2:
image: redis:7-alpine
ports: ["7002:6379"]
volumes: ["./conf/redis-2.conf:/usr/local/etc/redis/redis.conf"]
command: redis-server /usr/local/etc/redis/redis.conf
networks: [redis-cluster]
redis-master-3:
image: redis:7-alpine
ports: ["7003:6379"]
volumes: ["./conf/redis-3.conf:/usr/local/etc/redis/redis.conf"]
command: redis-server /usr/local/etc/redis/redis.conf
networks: [redis-cluster]
redis-replica-1:
image: redis:7-alpine
ports: ["7004:6379"]
volumes: ["./conf/redis-4.conf:/usr/local/etc/redis/redis.conf"]
command: redis-server /usr/local/etc/redis/redis.conf
depends_on: [redis-master-1, redis-master-2, redis-master-3]
networks: [redis-cluster]
redis-replica-2:
image: redis:7-alpine
ports: ["7005:6379"]
volumes: ["./conf/redis-5.conf:/usr/local/etc/redis/redis.conf"]
command: redis-server /usr/local/etc/redis/redis.conf
depends_on: [redis-master-1, redis-master-2, redis-master-3]
networks: [redis-cluster]
redis-replica-3:
image: redis:7-alpine
ports: ["7006:6379"]
volumes: ["./conf/redis-6.conf:/usr/local/etc/redis/redis.conf"]
command: redis-server /usr/local/etc/redis/redis.conf
depends_on: [redis-master-1, redis-master-2, redis-master-3]
networks: [redis-cluster]
cluster-init:
image: redis:7-alpine
depends_on:
- redis-master-1
- redis-master-2
- redis-master-3
- redis-replica-1
- redis-replica-2
- redis-replica-3
networks: [redis-cluster]
entrypoint: >
sh -c "
sleep 5 &&
redis-cli --cluster create
172.20.0.2:6379 172.20.0.3:6379 172.20.0.4:6379
172.20.0.5:6379 172.20.0.6:6379 172.20.0.7:6379
--cluster-replicas 1 --cluster-yes
"
sentinel-1:
image: redis:7-alpine
ports: ["26379:26379"]
volumes: ["./sentinel/sentinel-1.conf:/etc/redis/sentinel.conf"]
command: redis-sentinel /etc/redis/sentinel.conf
sentinel-2:
image: redis:7-alpine
ports: ["26380:26379"]
volumes: ["./sentinel/sentinel-2.conf:/etc/redis/sentinel.conf"]
command: redis-sentinel /etc/redis/sentinel.conf
sentinel-3:
image: redis:7-alpine
ports: ["26381:26379"]
volumes: ["./sentinel/sentinel-3.conf:/etc/redis/sentinel.conf"]
command: redis-sentinel /etc/redis/sentinel.conf
networks:
redis-cluster:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/24
YAML
Lab: Diagnóstico de Produção
cat > redis-healthcheck.sh << 'SCRIPT'
#!/bin/bash
set -euo pipefail
echo "=== REDIS HEALTH CHECK $(date) ==="
# 1. Ping
echo ""
echo "─── PING ───"
redis-cli PING
# 2. Info básico
echo ""
echo "─── INFORMAÇÕES GERAIS ───"
redis-cli INFO server | grep -E "redis_version|uptime_in_seconds|os"
redis-cli INFO clients | grep -E "connected_clients|blocked_clients"
# 3. Memória
echo ""
echo "─── MEMÓRIA ───"
redis-cli INFO memory | grep -E \
"used_memory_human|used_memory_rss_human|maxmemory_human|mem_fragmentation_ratio"
redis-cli MEMORY DOCTOR 2>/dev/null | head -5 || echo "MEMORY DOCTOR unavailable"
# 4. Performance
echo ""
echo "─── PERFORMANCE ───"
redis-cli INFO stats | grep -E \
"instantaneous_ops_per_sec|total_commands_processed|keyspace_hits|keyspace_misses"
# 5. Comandos lentos
echo ""
echo "─── SLOW LOG ───"
redis-cli SLOWLOG LEN
redis-cli SLOWLOG GET 3
# 6. Keyspace
echo ""
echo "─── KEYSPACE ───"
redis-cli INFO keyspace
redis-cli DBSIZE
# 7. Replicação (se cluster/sentinel)
echo ""
echo "─── REPLICAÇÃO ───"
redis-cli INFO replication | grep -E "role|connected_slaves|master_host|master_link_status" || true
# 8. Latência
echo ""
echo "─── LATÊNCIA (3s) ───"
redis-cli --latency -h localhost -p 6379 &
PID=$!
sleep 3
kill $PID 2>/dev/null || true
wait $PID 2>/dev/null || true
# 9. ACL (se configurado)
echo ""
echo "─── ACL ───"
redis-cli ACL LIST 2>/dev/null | head -3 || echo "ACL not configured"
# 10. Diagnóstico final
echo ""
echo "─── FIM ───"
FRAG=$(redis-cli INFO memory | grep mem_fragmentation_ratio | awk -F: '{print $2}' | tr -d '\r')
if (( $(echo "$FRAG > 1.5" | bc -l) )); then
echo "⚠️ Fragmentação alta: $FRAG (considere restart)"
elif (( $(echo "$FRAG < 1.0" | bc -l) )); then
echo "❌ Swapping detectado: $FRAG (aumente RAM ou ajuste maxmemory)"
else
echo "✅ Fragmentação saudável: $FRAG"
fi
SCRIPT
chmod +x redis-healthcheck.sh
RDB + AOF hybrid (Redis 7.4+) é o padrão de persistência recomendado. Sentinel para HA, Cluster para escala horizontal. INFO + SLOWLOG para monitoramento. ACL para segurança granular. rename-command para desabilitar comandos perigosos. THP deve ser desabilitado. vm.overcommit_memory = 1 é obrigatório.