Valkey – Guia rápido

Saudações.

Esse tutorial é um guia rápido de instalação e uso do Valkey, serviço de chave-valor e pub/sub semelhante ao Redis (fork antigo) e que hoje supera em muito o Redis.

Pré-requisitos (constam em outros artigos aqui do blog):

  • Instalação do Linux (Debian ou Alpine);
  • Internet no servidor (sua VPS ou host);
  • Docker CE instalado (opcional);

1 – Sobre Valkey

O Valkey é um software de banco de dados firmado no conceito de chave-valor armazenado em RAM, seguindo a filosofia “RAM is the new disk” (a memória é o novo disco).

Seus fundamentos são:

  • Chave/valor: Armazenar e recuperar o valor de chaves (nome=Patrick);
  • Cache: As chaves podem ter TTL (tempo de vida) e expirar se não forem renovadas;
  • Pub/sub: Um canal que funciona como sala de chat em tempo real para programas;
  • RAM como armazenamento principal;
  • Disco como backup das caches:
    • Backup em tempo real nos arquivos AOF (log de criação e alteração das chaves);
    • Backup completo em arquivos RDB (snapshots completos da memória);

Para que ele atinja velocidades extremas, o ambiente deve:

  • Possui baixa latência de rede;
  • Possuir uma CPU com muita memória CACHE (L1, L2, L3);
    • Recomendável: Mínimo 16 MB de CACHE total;
    • Ótimo: Mínimo 128 MB de CACHE (caro!);
  • Possuir memória de alta-velocidade (DDR4 ou superior);
  • Reservar núcleos exclusivos para que ele não perca o CACHE para outros programas;

As operações de backup AOF/RDB rodam em paralelo sem penalizar as operações, o uso de unidades NVME ou SSD ajudam a garantir a persistência contra desastres.

2 – Ajustes no sistema

Alguns ajustes são recomendados no sistema para atender melhor às demandas de alta-performance no Valkey.

Se você rodar ele com outros sistemas em um ambiente muito híbrido não será necessário mexer (você está em apuros mesmo).

2.1 – Ajustes básicos

Você deve, previamente:

  • Data/hora do servidor finamente sincronizada com NTP/NTS
  • Manter a coerência entre o IP do servidor e o nome de DNS (real ou fictício) no arquivo /etc/hosts
  • Possuir um DNS funcionando bem e rápido, configure o IP em /etc/resolv.conf

2.2 – Ajustes no sysfs

É necessário ativar o “tranparent hugepages” pois ele tentará fazer manutenção da memória RAM e isso pode interromper o Valkey por alguns microssegundos.

Bash
# - Criar manifesto de preenchimento de configs durenate o boot:
(
    echo 'w /sys/kernel/mm/transparent_hugepage/enabled  - - - - never';
) > /etc/tmpfiles.d/transp-hugepage-disable.conf;

# Desativar hugepages transparente imediatamente
echo never > /sys/kernel/mm/transparent_hugepage/enabled;

2.3 – Ajustes no sysctl

Esses ajustes mudam o comportamento padrão do Kernel Linux.

Bash
# Gestao de overcommit de memoria
echo  "vm.overcommit_memory=1"     > /etc/sysctl.d/076-ram-overcommit.conf;

# Aumentar capacidades de rede do protocolo TCP
(
    echo  "net.core.rmem_default=31457280";
    echo  "net.core.wmem_default=31457280";
    echo  "net.core.rmem_max=134217728";
    echo  "net.core.wmem_max=134217728";
    echo  "net.core.netdev_max_backlog=250000";
    echo  "net.core.optmem_max=33554432";
    echo  "net.core.default_qdisc=fq";
    echo  "net.core.somaxconn=65535";
) > /etc/sysctl.d/051-net-core.conf;

# Aumentar buffers e acelerar o inicio das conexoes
(
    echo "net.ipv4.tcp_sack = 1";
    echo "net.ipv4.tcp_timestamps = 1";
    echo "net.ipv4.tcp_low_latency = 1";
    echo "net.ipv4.tcp_max_syn_backlog = 65535";
    echo "net.ipv4.tcp_rmem = 4096 87380 67108864";
    echo "net.ipv4.tcp_wmem = 4096 65536 67108864";
    echo "net.ipv4.tcp_mem = 6672016 6682016 7185248";
    echo "net.ipv4.tcp_congestion_control=htcp";
    echo "net.ipv4.tcp_mtu_probing=1";
    echo "net.ipv4.tcp_moderate_rcvbuf =1";
    echo "net.ipv4.tcp_no_metrics_save = 1";
)  >  /etc/sysctl.d/052-net-tcp-ipv4.conf;

Aplicar alterações de sysctl:

Bash
# Comando (sysctl -p) requer tudo em um unico arquivo:
(
    echo "# NAO EDITAR";
    echo "# Gerado automaticamente via:";
    echo "# cat /etc/sysctl.d/*.conf > /etc/sysctl.conf";
    echo;
    cat /etc/sysctl.d/*.conf;
    echo;
) > /etc/sysctl.conf;

# Aplicar imediatamente:
sysctl -q --system  2>/dev/null;
sysctl -q -p        2>/dev/null;

3 – Valkey no Debian (host)

Esse capítulo aborda o uso do Valkey direto no HOST em um servidor Debian (VPS, VM).

Bash
# Atualizar sistema local
apt  -y  update;
apt  -y  upgrade;
apt  -y  dist-upgrade;
apt  -y  autoremove;

# Instalar o Valkey
apt  -y  install  valkey-tools;
apt  -y  install  valkey-server;
apt  -y  install  valkey-sentinel;

# Ativar serviço servidor durante o boot
systemctl  enable  valkey-server;
systemctl  enable  valkey-sentinel;

4 – Valkey no Alpine (host)

Esse capítulo aborda o uso do Valkey direto no HOST em um servidor Alpine (VPS, VM).

Bash
# Atualizar sistema local
apk  update;
apk  upgrade;

# Instalar o Valkey
apk  add  valkey;
apk  add  valkey-cli;
apk  add  valkey-tls;
apk  add  valkey-benchmark;

# Ativar serviço servidor durante o boot
rc-update  add  valkey           default;
rc-update  add  valkey-sentinel  default;

5 – Configurações básicas

Cada caso pede uma forma diferente de usar o Valkey, vou apresentar algumas configurações de exemplo.

As configurações podem ser passados para o valkey-server via argumentos ou pelo arquivo de configuração.

Nos argumentos vc deve preceder a palavra de “–” seguida de espaço e o valor. Exemplo:

5.1 – Cache puro em RAM

Exemplo rodando em linha de comando:

Bash
# Rodar valkey-server com argumentos na linha de comando:
# - Abrir apenas no IP de loopback ipv4 (127.0.0.1) e ipv6 (::1)
# - Porta 7000
# - Limite de RAM: 128 MB
# - Sem salvar nada em disco
/usr/bin/valkey-server \
    \
    --bind 127.0.0.1 ::1 \
    --port 7000 \
    --databases 256 \
    --maxmemory 128mb \
    --appendonly no \
    --dir /run \
    --save "" \
    --loglevel notice;

No arquivo de configuração basta informar uma palavra por linha seguida de espaço e o valor. Exemplo:

Arquivo: /etc/valkey/valkey-server-cache.conf
bind        127.0.0.1 ::1
port        7000
databases   256
maxmemory   128mb
appendonly  no
dir         /run
save        ""
loglevel    notice

Rodando baseado no arquivo acima (/etc/valkey/valkey-server-cache.conf):

Bash
# Rodar usando configuracao especifica:
# - Modo debug:
/usr/bin/valkey-server /etc/valkey/valkey-server-cache.conf --loglevel verbose;

# - Modo normal:
/usr/bin/valkey-server /etc/valkey/valkey-server-cache.conf;

5.2 – Persistência Básica

Nessa configuração o Valkey irá armazenar as chaves alteradas periodicamente de maneira relaxada, sem urgência.

Pode perder dados em casos de panes por falta de memória (OOM), assassinato do serviço ou desligamento acidental do servidor.

Arquivo: /etc/valkey/valkey-server-db-relax.conf
# Porta de escuta
bind            127.0.0.1 ::1
port            7001

# Opcoes
pidfile         /run/valkey/valkey-7001.pid
logfile         /var/log/valkey/valkey-7001.log
loglevel        notice
protected-mode  no
tcp-backlog     4096
timeout         0
tcp-keepalive   30

# Persistência relaxada
# RDB Snapshots:
dir             /var/lib/valkey
dbfilename      valkey-7001.rdb
save            900  1
save            300  100
save            60   10000
rdbcompression  no
rdbchecksum     yes

# AOF timeline
appendonly      yes
appendfilename  valkey-7001.aof
appenddirname   aof7001
appendfsync     everysec

no-appendfsync-on-rewrite    yes
auto-aof-rewrite-percentage  100
auto-aof-rewrite-min-size    64mb
aof-load-truncated           yes
aof-use-rdb-preamble         yes

# Gestao de Memoria
maxmemory               256mb
maxmemory-policy        allkeys-lru
maxmemory-samples       5
lazyfree-lazy-eviction  yes
lazyfree-lazy-expire    yes

# Performance em Ambientes Saturados
hz         10
dynamic-hz yes
io-threads 2

Rodando baseado no arquivo acima (/etc/valkey/valkey-server-db-relax.conf):

Bash
# Rodar usando configuracao especifica:
# - Modo debug:
/usr/bin/valkey-server /etc/valkey/valkey-server-db-relax.conf --loglevel verbose;

# - Modo normal:
/usr/bin/valkey-server /etc/valkey/valkey-server-db-relax.conf;

5.3 – Persistência em tempo real

Essa configuração é focada em casos onde você deseja que o Valkey seja seu banco de dados persistente sem abrir margem para a perda de nenhuma chave, ou seja, o banco de dados na memória será salvo em disco a cada byte alterado usando apenas AOF (o RDB cria pontos no tempo que podem ficar atrasados em relação ao AOF).

Arquivo: /etc/valkey/valkey-server-database.conf
# Porta de escuta
bind            127.0.0.1 ::1
port            7002

# Opcoes
pidfile         /run/valkey/valkey-7002.pid
logfile         /var/log/valkey/valkey-7002.log
loglevel        notice
protected-mode  no
tcp-backlog     4096
timeout         0
tcp-keepalive   30

# Persistência relaxada
# RDB Snapshots:
dir             /var/lib/valkey
dbfilename      valkey-7002.rdb
save            ""
rdbcompression  no
rdbchecksum     yes

# AOF timeline
appendonly      yes
appendfilename  valkey-7002.aof
appenddirname   aof7002
appendfsync     always

no-appendfsync-on-rewrite    no
auto-aof-rewrite-percentage  100
auto-aof-rewrite-min-size    64mb
aof-load-truncated           yes
aof-use-rdb-preamble         no

# Gestao de Memoria
maxmemory               256mb
maxmemory-policy        allkeys-lru
maxmemory-samples       5
lazyfree-lazy-eviction  yes
lazyfree-lazy-expire    yes

# Performance em Ambientes Saturados
hz         10
dynamic-hz yes
io-threads 2

Rodando baseado no arquivo acima (/etc/valkey/valkey-server-database.conf):

Bash
# Rodar usando configuracao especifica:
/usr/bin/valkey-server /etc/valkey/valkey-server-database.conf;

6 – Rodando Valkey no Docker

O Valkey tem imagens para Docker finamente compiladas para alta performance.

Vou começar pela execução mais simples para estudos usando “docker run”.

6.1 – Rede Docker

Padrão “network_public” que costumo usar nos meus tutoriais:

Bash
# Rede de containers FreeRadius
docker network create network_public \
    -d bridge \
    -o com.docker.network.bridge.name=br-net-public \
    -o com.docker.network.driver.mtu=1500 \
    -o com.docker.network.bridge.gateway_mode_ipv4=nat-unprotected \
    --subnet 10.249.0.0/16 \
    --gateway 10.249.255.254;

6.2 – Container para Cache puro em RAM

Container sem uso de disco, apenas memória. Observe que reservei no container a mesma quantidade de memória que informei ao valkey-server (192 MB):

Bash
# Rodar valkey-server em container
# - Limite de RAM: 128 MB
# - Reserva de RAM: 192 MB
# - Sem salvar nada em disco

# Baixar imagem
    docker pull valkey/valkey:9.0.3;

# Renovar/rodar
    docker rm -f valkey-cache 2>/dev/null;
    docker run \
        -d --restart=always \
        --name valkey-cache \
        -h valkey-cache.intranet.br \
        \
        --tmpfs /run:rw,noexec,nosuid,size=16m \
        --read-only \
        \
        --cpus=1 \
        --memory=256m \
        --memory-swap=256m \
        --memory-reservation=192m \
        --oom-score-adj=-500 \
        \
        --ulimit nofile=1048576:1048576 \
        --ulimit memlock=-1 \
        --sysctl net.core.somaxconn=16384 \
        \
        --network network_public \
        \
        --health-cmd="valkey-cli -p 6379 ping | grep -q PONG" \
        --health-interval=5s \
        --health-timeout=3s \
        --health-start-period=10s \
        --health-retries=3 \
        \
        valkey/valkey:9.0.3 \
            valkey-server \
                --bind           '0.0.0.0 ::' \
                --port           6379 \
                --protected-mode no \
                --set-proc-title no \
                --tcp-backlog    16384 \
                --tcp-keepalive  30 \
                --timeout 0 \
                \
                --databases 256 \
                \
                --maxmemory 192mb \
                \
                --appendonly no \
                --dir /run \
                --save "" \
                \
                --loglevel notice;

Analisando e rodando testes no container:

Bash
# Analisando
    docker inspect  valkey-cache;
    docker diff     valkey-cache;
    docker logs     valkey-cache;
    docker logs -f  valkey-cache;

# Testar se o container está funcionando:
    docker exec -it valkey-cache valkey-cli -p 6379 ping;

# Obter terminal valkey-cli:
    docker exec -it valkey-cache valkey-cli;

6.2 – Container com Persistência Básica

Container com persistência básica em disco (volume):

Bash
# Rodar valkey-server em container
# - Limite de RAM: 384 MB
# - Reserva de RAM: 256 MB
# - Sem salvar nada em disco

# Pasta para salvar dados no volume
    mkdir -p /storage/valkey-db-relax;

# Ajuste de permissao na pasta do volume
    chown -R 999:999 /storage/valkey-db-relax;

# Renovar/rodar
    docker rm -f valkey-db-relax 2>/dev/null;
    docker run \
        -d --restart=always \
        --name valkey-db-relax \
        -h valkey-db-relax.intranet.br \
        \
        --read-only \
        --tmpfs /run:rw,noexec,nosuid,size=16m \
        \
        --cpus=1 \
        --memory=384m \
        --memory-swap=384m \
        --memory-reservation=256m \
        --oom-score-adj=-500 \
        \
        --ulimit nofile=1048576:1048576 \
        --ulimit memlock=-1 \
        --sysctl net.core.somaxconn=16384 \
        \
        --network network_public \
        \
        -v /storage/valkey-db-relax:/data \
        -w /data \
        \
        --health-cmd="valkey-cli -p 6379 ping | grep -q PONG" \
        --health-interval=5s \
        --health-timeout=3s \
        --health-start-period=10s \
        --health-retries=3 \
        \
        valkey/valkey:9.0.3 \
            valkey-server \
                --bind            '0.0.0.0 ::' \
                --port            6379 \
                --loglevel        notice \
                --protected-mode  no \
                --tcp-backlog     4096 \
                --timeout         0 \
                --tcp-keepalive   30 \
                --dir             /data \
                --dbfilename      valkey-db-relax.rdb \
                --save            900  1 \
                --save            300  100 \
                --save            60   10000 \
                --rdbcompression  no \
                --rdbchecksum     yes \
                \
                --appendonly      yes \
                --appendfilename  valkey-db-relax.aof \
                --appenddirname   aof-db-relax \
                --appendfsync     everysec \
                \
                --no-appendfsync-on-rewrite    yes \
                --auto-aof-rewrite-percentage  100 \
                --auto-aof-rewrite-min-size    64mb \
                --aof-load-truncated           yes \
                --aof-use-rdb-preamble         yes \
                \
                --maxmemory               256mb \
                --maxmemory-policy        allkeys-lru \
                --maxmemory-samples       5 \
                --lazyfree-lazy-eviction  yes \
                --lazyfree-lazy-expire    yes \
                \
                --hz         10 \
                --dynamic-hz yes \
                --io-threads 2;

Analisando e rodando testes no container “valkey-db-relax“:

Bash
# Analisando
    docker inspect  valkey-db-relax;
    docker diff     valkey-db-relax;
    docker logs     valkey-db-relax;
    docker logs -f  valkey-db-relax;

# Testar se o container está funcionando:
    docker exec -it valkey-db-relax valkey-cli -p 6379 ping;

# Obter terminal valkey-cli:
    docker exec -it valkey-db-relax valkey-cli;

6.3 – Container com Persistência em Tempo Real

Container focado em dados persistente sem abrir margem para a perda de nenhuma chave (AOF ativo, sem RDB).

Bash
# Rodar valkey-server em container
# - Limite de RAM: 1280 MB
# - Reserva de RAM: 1024 MB
# - Salvando em AOF

# Pasta para salvar dados no volume
    mkdir -p /storage/valkey-database;

# Ajuste de permissao na pasta do volume
    chown -R 999:999 /storage/valkey-database;

# Renovar/rodar
    docker rm -f valkey-database 2>/dev/null;
    docker run \
        -d --restart=always \
        --name valkey-database \
        -h valkey-database.intranet.br \
        \
        --read-only \
        --tmpfs /run:rw,noexec,nosuid,size=16m \
        \
        --cpus=4 \
        --memory=1280m \
        --memory-swap=1280m \
        --memory-reservation=1024m \
        --oom-score-adj=-500 \
        \
        --ulimit nofile=1048576:1048576 \
        --ulimit memlock=-1 \
        --sysctl net.core.somaxconn=16384 \
        \
        --network network_public \
        \
        -v /storage/valkey-database:/data \
        -w /data \
        \
        --health-cmd="valkey-cli -p 6379 ping | grep -q PONG" \
        --health-interval=5s \
        --health-timeout=3s \
        --health-start-period=10s \
        --health-retries=3 \
        \
        valkey/valkey:9.0.3 \
            valkey-server \
                --bind            '0.0.0.0 ::' \
                --port            6379 \
                --loglevel        notice \
                --protected-mode  no \
                --tcp-backlog     4096 \
                --timeout         0 \
                --tcp-keepalive   30 \
                --dir             /data \
                --dbfilename      valkey-database.rdb \
                --save            "" \
                --rdbcompression  no \
                --rdbchecksum     yes \
                \
                --appendonly      yes \
                --appendfilename  valkey-database.aof \
                --appenddirname   aof-database \
                --appendfsync     always \
                \
                --no-appendfsync-on-rewrite    no \
                --auto-aof-rewrite-percentage  100 \
                --auto-aof-rewrite-min-size    64mb \
                --aof-load-truncated           yes \
                --aof-use-rdb-preamble         no \
                \
                --maxmemory               1024mb \
                --maxmemory-policy        allkeys-lru \
                --maxmemory-samples       5 \
                --lazyfree-lazy-eviction  yes \
                --lazyfree-lazy-expire    yes \
                \
                --hz         10 \
                --dynamic-hz yes \
                --io-threads 2;

Analisando e rodando testes no container “valkey-database“:

Bash
# Analisando
    docker inspect  valkey-database;
    docker diff     valkey-database;
    docker logs     valkey-database;
    docker logs -f  valkey-database;

# Testar se o container está funcionando:
    docker exec -it valkey-database valkey-cli -p 6379 ping;

# Obter terminal valkey-cli:
    docker exec -it valkey-database valkey-cli;

7 – Testes de performance

Os testes são importantes para comparar como o Valkey se comporta com cada configuração, cada limite e cada hardware diferente.

Você deve rodar o comando “valkey-benchmark” no mesmo ambiente (HOST ou container) onde está o valyer-server ou informar o IP (descubra em docker inspect).

Bash
# Testes de capacidade (loopback test)

# 1 - Testes basicos do Redis
# 1.1 - Use 20 parallel clients, for a total of 100k requests:
valkey-benchmark -h 127.0.0.1 -p 6379 -n 100000 -c 20;
    # Summary:
    #   throughput summary: 44762.76 requests per second
    #   latency summary (msec):
    #           avg       min       p50       p95       p99       max
    #         0.240     0.088     0.239     0.271     0.423     1.455


# 1.2 - Fill 127.0.0.1:6379 with about 1 million keys only using the SET test:
valkey-benchmark -t set -n 1000000 -r 100000000;
    # Summary:
    #   throughput summary: 46251.33 requests per second
    #   latency summary (msec):
    #           avg       min       p50       p95       p99       max
    #         0.563     0.176     0.559     0.687     0.879     4.247

# 1.3 - Benchmark 127.0.0.1:6379 for a few commands producing CSV output:
valkey-benchmark -t ping,set,get -n 100000 --csv;

# 1.4 - Benchmark a specific command line:
valkey-benchmark -r 10000 -n 10000 eval 'return redis.call("ping")' 0;
    # Summary:
    #   throughput summary: 46511.63 requests per second
    #   latency summary (msec):
    #           avg       min       p50       p95       p99       max
    #         0.564     0.160     0.551     0.639     0.887     2.519

# 1.5 - Fill a list with 10000 random elements:
valkey-benchmark -r 10000 -n 10000 lpush mylist __rand_int__;
    # Summary:
    #   throughput summary: 43290.04 requests per second
    #   latency summary (msec):
    #           avg       min       p50       p95       p99       max
    #         0.596     0.152     0.575     0.703     0.839     2.327

# 2.0 - Teste realista:
#     - 20 mil requisicoes
#     - fazer 1.000 requisoes em paralelo
#     - criar chaves com valores de 1024 bytes
#     - 8 threads de CPU em paralelo
#     - pipilene de 8 requisicoes em serie
#     - 6 digitos de precisao no resultado
valkey-benchmark \
    -h 127.0.0.1 -p 6379 \
    -n 20000 -c 1000 \
    -d 1024 \
    --threads 8 \
    -P 8 \
    --precision 6;
   # Summary:
   #   throughput summary: 78125.00 requests per second
   #   latency summary (msec):
   #           avg       min       p50       p95       p99       max
   #        26.382     2.024    28.655    34.999    48.239    61.807
 

8 – Configurações Comentadas

Todas as configurações com comentários:

Arquivo: /etc/redis/redis.conf
# ==============================================================================
# VALKEY - Arquivo de Configuração
# Compatível com Valkey 7.2+ / 8.x
# Baseado em configuração Redis adaptada para Valkey
# ==============================================================================

# - bind: informa em quais IPs o VALKEY escutará as requisições
#         ao configurar apenas IPs de loopback (127.0.0.1 e ::1)
#         o VALKEY não abrirá a escuta nos IPs das interfaces de rede
#         e estará exclusivo para uso interno do HOST
#         Se voce colocar 0.0.0.0 e :: você abrirá o VALKEY em todos
#         os IPs e isso requerirá a implementação de autenticação.
bind 127.0.0.1 ::1

# Porta do VALKEY
port 6379

# No modo protegido (yes), se você nao informar mecanismos de autenticação
# o VALKEY não abrirá portas nos IPs das interfaces de rede.
protected-mode yes

# Número de conexões aguardando atendimento
tcp-backlog 511

# Tempo de inatividade antes de fechar a conexão com o cliente, 0=manter pra sempre
timeout 0

# Intervalo entre mensagens de keepalive para manter a conexão ativa,
# importante para impedir a quebra da conexão quando ela atravessa um NAT/CGNAT
tcp-keepalive 30

# Modo daemon, yes para rodar em background (modo HOST),
# no para rodar em foreground (importante no modo DOCKER para segurar o exec)
daemonize yes

# Arquivo para gravar o PID do processo
pidfile /run/valkey/valkey-server.pid

# Nivel de log, opcoes: debug, verbose, notice, warning
loglevel notice

# Arquivo de log para depurar eventos internos e erros
logfile /var/log/valkey/valkey.log

# Total de bases de dados suportadas (de 0 a 15)
# - 16 é o número máximo suportado
databases 16

# Nao exibir mensagem de saudação ao conectar no VALKEY
always-show-logo no

# Alterar argumentos exibidos na lista de processos do Linux
set-proc-title yes
# Formato da nova mensagem de argumentos exibidos na lista de processos do Linux
# opcao util caso você informe a senha no argumento, assim ao modificar
# o argumento a senha deixa de ser exibida na lista de processos.
proc-title-template "{title} {listen-addr} {server-mode}"


#------------------------------------- THREADS DE I/O (exclusivo Valkey)
# O Valkey melhorou significativamente o suporte a multi-threading em relação
# ao Redis original. As threads de I/O permitem que operações de leitura e
# escrita de rede sejam paralelizadas, aumentando o throughput em servidores
# com múltiplos núcleos.
#
# - io-threads: número de threads para processar I/O de rede.
#   Use 1 para manter o comportamento single-thread (padrão do Redis legado).
#   Para servidores com 4+ núcleos, valores entre 2 e 6 são recomendados.
#   ATENÇÃO: não defina mais threads do que núcleos físicos disponíveis.
io-threads 1

# - io-threads-do-reads: habilita o uso das threads de I/O também para
#   operações de leitura (além das escritas).
#   - yes habilita leitura multi-thread (maior throughput em cargas mistas)
#   - no reserva as threads apenas para escritas (padrão mais conservador)
io-threads-do-reads no


#------------------------------------- SEGURANÇA DE DADOS

# Modo de segurança de dados: ao colocar como yes o VALKEY para
# de aceitar novas escritas se as rotinas que salvam os dados
# no disco derem erro
stop-writes-on-bgsave-error yes


#------------------------------------- RDB - Salvamento de dados

# Ativar compressao de dados:
# - yes ativa compressão LZF (levemente mais lento, ocupa menos espaço em disco)
# - no grava os dados sem compressão (mais rápido mas ocupa mais espaço em disco)
rdbcompression yes

# Inserir checksum para impedir/detectar corrupção de registros no armazenamento
# - yes ajuda a evitar corrupções e panes entre restarts acidentais
# - no ajuda a deixar o salvamento em disco mais rápido, porem mais sensível a
#   danos.
rdbchecksum yes

# Arquivo em disco onde as chaves de RAM serão salvas
dbfilename valkey_6379_dump.rdb

# Deletar arquivo RDB danificado?
# - yes para deletar arquivos corrompidos e continuar sem eles,
# - no para manter o arquivo para analise e recuperações
#   caso os dados sejam importantes
rdb-del-sync-files no

# Pasta onde os arquivos RDB serão gravados, prefira
# sempre informar uma pasta montada em um sistema de alta velocidade
# como SSD/NVME
dir /var/lib/valkey/


#------------------------------------- AOF - Salvamento de dados

# Ativar modo AOF?
# - yes ativa o registro de todas as operações para recuperação exata
# - no deixa o modo AOF desativado (padrão)
appendonly no

# Arquivo de registro de todas operações
appendfilename "appendonly.aof"

# Sub-diretório onde os arquivos de AOF serão gravados no disco
# Esse diretório ficará dentro da pasta definida na config [dir]
# por padrão em: /var/lib/valkey/ + [appenddirname]
# Caminho final: /var/lib/valkey/appendonlydir/
appenddirname "appendonlydir"

# Frequencia de gravação das operações no AOF por meio de um pedido
# de sync() ao sistema operacional.
# - everysec: de 1 em 1 segundo (equilíbrio entre desempenho e segurança)
# - always: sempre que houver qualquer gravação de chaves ou expiração
#            (máxima segurança, menor desempenho)
# - no: deixar que o sistema operacional decida quando efetivar a escrita atrasada
#        (maior desempenho, maior risco de perda de dados)
appendfsync everysec

# Controlar se haverá pause na sincronização do AOF
# durante uma reescrita do arquivo.
# - yes pausa a sincronizacao durante reescritas, melhor desempenho mas
#   abre a possibilidade da perda de dados se o servidor VALKEY
#   for desligado da energia durante a reescrita
# - no faz com que a reescrita não pause a chamada do sync() ao sistema operacional
#   durante as reescritas
no-appendfsync-on-rewrite no

# Percentual de crescimento do AOF para disparar uma reescrita automática.
# Quando o arquivo AOF crescer X% em relação ao tamanho que tinha após
# a última reescrita, uma nova reescrita é acionada.
# - 100 significa que o arquivo precisa dobrar de tamanho para acionar a reescrita
# - 0 desativa a reescrita automática por crescimento percentual
auto-aof-rewrite-percentage 100

# Tamanho mínimo que o arquivo AOF precisa ter para que a reescrita automática
# seja acionada. Impede reescritas frequentes quando o arquivo ainda é pequeno.
auto-aof-rewrite-min-size 64mb

# Aceitar arquivos AOF truncados (incompletos) na inicialização?
# - yes carrega os dados disponíveis e ignora o final truncado
#   (útil após falhas de energia no meio de uma escrita)
# - no recusa o arquivo truncado e exige intervenção manual
aof-load-truncated yes

# Usar preâmbulo RDB no arquivo AOF?
# - yes grava um snapshot RDB no início do AOF, acelerando o carregamento
#   inicial pois não precisa replayer todas as operações desde o início
# - no grava apenas os comandos AOF puros
aof-use-rdb-preamble yes

# Registrar timestamp em cada entrada AOF?
# - yes adiciona marcação temporal nas entradas (útil para PITR - Point-in-Time Recovery)
# - no mantém o formato padrão sem timestamps
# ATENÇÃO: ao ativar, o arquivo AOF não será compatível com versões
# mais antigas do Redis/Valkey que não suportam timestamps
aof-timestamp-enabled no


#------------------------------------- REPLICAÇÃO

# Permitir que réplicas respondam requisições com dados potencialmente
# desatualizados enquanto estão sincronizando com o primário?
# - yes permite leitura de dados defasados (maior disponibilidade)
# - no retorna erro enquanto a réplica não está sincronizada (maior consistência)
replica-serve-stale-data yes

# Réplicas aceitam apenas leitura?
# - yes impede escritas diretas na réplica (recomendado)
# - no permite escritas diretas (pode causar divergência de dados)
replica-read-only yes

# Usar transferência RDB sem disco ao sincronizar réplicas?
# - yes o primário transmite o RDB diretamente pela rede (sem gravar em disco)
#        ideal para SSDs com escrita limitada ou muitas réplicas simultâneas
# - no grava o RDB em disco antes de enviar à réplica (modo clássico)
repl-diskless-sync yes

# Tempo de espera (em segundos) antes de iniciar a sincronização diskless,
# permitindo que mais réplicas se conectem e recebam o mesmo RDB simultaneamente
repl-diskless-sync-delay 5

# Número máximo de réplicas que receberão a sincronização diskless simultânea.
# - 0 sem limite (aguarda apenas o delay acima)
repl-diskless-sync-max-replicas 0

# Modo de carregamento diskless na réplica:
# - disabled a réplica grava o RDB em disco antes de carregá-lo (padrão seguro)
# - on-empty-db carrega diretamente na memória apenas se a réplica estiver vazia
# - swapdb troca o banco em memória diretamente (experimental, risco de OOM)
repl-diskless-load disabled

# Desativar o algoritmo Nagle (TCP_NODELAY) na conexão de replicação?
# - no mantém TCP_NODELAY desativado: envia pacotes imediatamente,
#    menor latência de replicação mas maior uso de banda
# - yes ativa agrupamento de pacotes (Nagle): menor uso de banda,
#    maior latência de replicação
repl-disable-tcp-nodelay no

# Prioridade da réplica para eleição como primário (menor = maior prioridade).
# - 0 impede que a réplica seja promovida a primário
replica-priority 100


#------------------------------------- ACL (Controle de Acesso)

# Tamanho máximo do log de tentativas de acesso via ACL
acllog-max-len 128


#------------------------------------- LIBERAÇÃO PREGUIÇOSA (LAZY FREE)
# Operações de deleção em memória podem bloquear o servidor quando
# envolvem estruturas muito grandes. O modo lazy free executa a liberação
# de memória em background, evitando travamentos.

# Liberar memória em background durante evicção por política de memória cheia?
# - yes evita travamentos durante evicção (recomendado com maxmemory ativo)
# - no deleta sincronicamente (pode travar por milissegundos)
lazyfree-lazy-eviction no

# Liberar chaves expiradas em background?
# - yes processa expirações de forma assíncrona
# - no processa expirações sincronamente
lazyfree-lazy-expire no

# Usar lazy free para deleções internas do servidor (ex: substituição de chaves)?
# - yes proteção contra travamentos em deleções implícitas
# - no comportamento síncrono padrão
lazyfree-lazy-server-del no

# Usar lazy free ao limpar base de dados de uma réplica durante sincronização?
# - yes evita bloqueio durante FLUSHALL em sincronização de réplica
# - no limpa a base de forma síncrona
replica-lazy-flush no

# Usar lazy free para comandos DEL explícitos do usuário?
# - yes faz DEL se comportar como UNLINK (assíncrono)
# - no mantém DEL síncrono (padrão compatível)
lazyfree-lazy-user-del no

# Usar lazy free para comandos FLUSHALL/FLUSHDB do usuário?
# - yes torna o FLUSH assíncrono
# - no FLUSH síncrono (padrão)
lazyfree-lazy-user-flush no


#------------------------------------- OOM SCORE ADJUSTMENT
# Ajuste da pontuação OOM (Out-Of-Memory Killer) do Linux para os processos
# do Valkey. Valores maiores = maior chance de ser encerrado pelo kernel
# em situação de falta de memória.

# - no  não ajusta as pontuações OOM (padrão)
# - yes ajusta usando os valores abaixo
# - absolute define os valores diretamente (sem considerar o valor atual)
oom-score-adj no

# Pontuações OOM para: [server] [replica] [background-child]
# - server: processo principal (0 = nunca matar, ideal para primário)
# - replica: processo de réplica (200 = baixa prioridade de proteção)
# - background-child: processo de bgsave/bgrewrite (800 = sacrificável primeiro)
oom-score-adj-values 0 200 800

# Desativar Transparent Huge Pages (THP)?
# - yes desativa THP, reduzindo latência e uso de memória em processos fork
#   (RECOMENDADO para produção)
# - no mantém THP ativado pelo kernel (pode causar picos de latência)
disable-thp yes


#------------------------------------- SLOW LOG

# Registrar comandos que demorem mais que X microsegundos (10000 = 10ms).
# Use -1 para desativar, 0 para registrar todos os comandos.
slowlog-log-slower-than 10000

# Número máximo de entradas mantidas no slow log
slowlog-max-len 128


#------------------------------------- MONITORAMENTO DE LATÊNCIA

# Limite em milissegundos para registrar eventos de latência.
# - 0 desativa o monitoramento de latência
# - Ex: 100 registra eventos com latência acima de 100ms
latency-monitor-threshold 0


#------------------------------------- NOTIFICAÇÕES DE KEYSPACE

# Habilitar notificações de eventos de keyspace via Pub/Sub.
# String de configuração com combinação de letras:
#   K = notificações de keyspace (__keyspace@<db>__)
#   E = notificações de keyevent  (__keyevent@<db>__)
#   g = comandos genéricos (DEL, EXPIRE, RENAME...)
#   $ = comandos de string
#   l = comandos de list
#   s = comandos de set
#   h = comandos de hash
#   z = comandos de sorted set
#   x = eventos de expiração
#   d = eventos de módulo
#   t = comandos de stream
#   m = eventos de miss de chave (quando uma chave não existe)
#   A = atalho para todos os eventos (exceto m)
# Ex: "KEA" ativa notificações completas de keyspace e keyevent
# "" desativa todas as notificações (padrão, sem custo de CPU)
notify-keyspace-events ""


#------------------------------------- OTIMIZAÇÕES DE ESTRUTURA DE DADOS
# O Valkey usa representações compactas (listpack/ziplist) para estruturas
# pequenas, economizando memória. Acima dos limites abaixo, converte para
# a estrutura completa (hashtable, skiplist, etc.)

# Hash: limite para uso de listpack (compacto)
hash-max-listpack-entries 512
hash-max-listpack-value 64

# List: limite de tamanho por nó interno
# Valores negativos são limites em bytes: -1=4KB, -2=8KB, -3=16KB, -4=32KB, -5=64KB
list-max-listpack-size -2
# Compressão de nós internos da lista (0 = sem compressão)
# Ex: 1 comprime todos exceto o primeiro e o último nó
list-compress-depth 0

# Set de inteiros: limite para usar intset (compacto)
set-max-intset-entries 512

# Sorted Set: limite para uso de listpack (compacto)
zset-max-listpack-entries 128
zset-max-listpack-value 64

# HyperLogLog: limite para usar representação esparsa (compacta)
hll-sparse-max-bytes 3000

# Stream: limites por nó interno da estrutura de stream
stream-node-max-bytes 4096
stream-node-max-entries 100


#------------------------------------- DESEMPENHO GERAL

# Rehashar tabelas de hash em background de forma ativa?
# - yes redistribui buckets gradualmente entre operações (recomendado)
# - no aguarda pressão de memória para rehash
activerehashing yes

# Limites do buffer de saída por tipo de cliente:
# Formato: [tipo] [hard-limit] [soft-limit] [soft-seconds]
# - hard-limit: desconecta imediatamente ao atingir
# - soft-limit + soft-seconds: desconecta se permanecer acima por X segundos
# - 0 = sem limite
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60

# Frequência base do loop de eventos do servidor (operações por segundo).
# - Controla timers internos: expiração de chaves, reconexões, etc.
# - Valores entre 1 e 500; padrão 10 é adequado para maioria dos casos
hz 10

# Ajuste dinâmico do hz conforme número de clientes conectados?
# - yes aumenta o hz automaticamente quando há mais clientes ativos,
#   reduzindo latência em momentos de alta carga
# - no mantém hz fixo conforme configurado acima
dynamic-hz yes

# Sincronização incremental ao reescrever arquivo AOF?
# - yes sincroniza a cada 32MB durante reescrita, evitando picos de I/O
# - no sincroniza tudo ao final (pode causar stall de disco em arquivos grandes)
aof-rewrite-incremental-fsync yes

# Sincronização incremental ao salvar arquivo RDB?
# - yes sincroniza a cada 32MB durante o bgsave, evitando picos de I/O
# - no sincroniza tudo ao final
rdb-save-incremental-fsync yes

# Usar thread em background para desfragmentação do alocador jemalloc?
# - yes reduz uso de memória física ao longo do tempo (recomendado)
# - no desativa a desfragmentação em background
jemalloc-bg-thread yes

.

A rapidez, que é uma virtude,
gera um vício, que é a pressa.
Gregório Marañón

Terminamos por hoje!

Patrick Brandão, patrickbrandao@gmail.com