← Voltar ao blog

Redis no Magento 2 para cache e sessões: configuração completa

Rodrigo Biazzi

O Redis é o backend padrão para cache e sessões do Magento 2. O cache em arquivos que vem de fábrica serve para a máquina de um dev, mas numa loja de verdade vira milhares de arquivos pequenos, limpezas de cache lentas e problemas de lock assim que você adiciona um segundo web node. Este guia mostra como configurar o Redis para o cache padrão, o page cache e as sessões no Magento Open Source e no Adobe Commerce 2.4.8, quais configurações do app/etc/env.php importam e os erros que mais causam problema em produção.

Três funções, três bancos

O Magento pode usar o Redis para três coisas diferentes:

  • Cache padrão: configuração, layout, blocks, metadados do EAV, dados de reflection e todos os outros tipos de cache, exceto o full page cache.
  • Page cache: o full page cache nativo, usado quando você não roda Varnish.
  • Sessões: sessões PHP de clientes e do admin.

Mantenha tudo separado. No mínimo, use números de database diferentes no Redis. Melhor ainda, rode as sessões numa instância de Redis separada do cache. O motivo é a eviction. Dados de cache podem ser descartados a qualquer momento e o Magento reconstrói. Dados de sessão não. Se os dois ficam numa instância com uma política de eviction que remove chaves sob pressão de memória, um pico de cache pode deslogar clientes e esvaziar os carrinhos deles.

Se o Varnish cuida do full page cache, você não precisa do page cache no Redis. O Magento só grava no frontend de page cache quando o FPC nativo está selecionado em Stores, Configuration, Advanced, System, Full Page Cache.

Configure o cache com setup:config:set

O jeito mais rápido de gravar a configuração é pela CLI. Ela atualiza o app/etc/env.php para você:

bin/magento setup:config:set \
  --cache-backend=redis \
  --cache-backend-redis-server=127.0.0.1 \
  --cache-backend-redis-port=6379 \
  --cache-backend-redis-db=0

bin/magento setup:config:set \
  --page-cache=redis \
  --page-cache-redis-server=127.0.0.1 \
  --page-cache-redis-port=6379 \
  --page-cache-redis-db=1

bin/magento setup:config:set \
  --session-save=redis \
  --session-save-redis-host=127.0.0.1 \
  --session-save-redis-port=6380 \
  --session-save-redis-db=0

Neste exemplo o cache usa uma instância na porta 6379 e as sessões usam uma segunda instância na porta 6380. Ajuste hosts e portas ao seu ambiente. Depois da mudança, faça um flush de cache uma vez para não sobrar nada antigo no backend de arquivos.

Como o env.php deve ficar

Em algum momento você vai querer editar o arquivo na mão, então ajuda conhecer a estrutura. Uma seção de cache típica é assim:

'cache' => [
    'frontend' => [
        'default' => [
            'id_prefix' => 'a1b_',
            'backend' => 'Magento\\Framework\\Cache\\Backend\\Redis',
            'backend_options' => [
                'server' => '127.0.0.1',
                'database' => '0',
                'port' => '6379',
                'password' => '',
                'compress_data' => '1',
                'compression_lib' => ''
            ]
        ],
        'page_cache' => [
            'id_prefix' => 'a1b_',
            'backend' => 'Magento\\Framework\\Cache\\Backend\\Redis',
            'backend_options' => [
                'server' => '127.0.0.1',
                'database' => '1',
                'port' => '6379',
                'password' => '',
                'compress_data' => '0'
            ]
        ]
    ],
    'allow_parallel_generation' => false
],

Algumas notas sobre essas chaves:

  • id_prefix é colocado na frente de todas as chaves. Se duas instalações do Magento compartilham um database do Redis, por exemplo staging e produção na mesma máquina, um prefixo único evita que uma leia os dados da outra. Databases separados continuam sendo a opção mais limpa.
  • compress_data troca um pouco de CPU por memória e tráfego de rede. Para o cache padrão normalmente compensa, porque as entradas de layout e config são grandes e comprimem bem.
  • allow_parallel_generation controla se vários processos podem montar o mesmo cache de config ao mesmo tempo. Deixar em false significa que um processo monta e os outros esperam, o que evita um monte de workers PHP regenerando a config depois de um flush.

Configurações de sessão que importam

O bloco de sessão tem mais opções do que a maioria das pessoas mexe, e algumas valem ser entendidas:

'session' => [
    'save' => 'redis',
    'redis' => [
        'host' => '127.0.0.1',
        'port' => '6380',
        'password' => '',
        'timeout' => '2.5',
        'persistent_identifier' => '',
        'database' => '0',
        'compression_threshold' => '2048',
        'compression_library' => 'gzip',
        'log_level' => '1',
        'max_concurrency' => '6',
        'break_after_frontend' => '5',
        'break_after_adminhtml' => '30',
        'first_lifetime' => '600',
        'bot_first_lifetime' => '60',
        'bot_lifetime' => '7200',
        'disable_locking' => '0',
        'min_lifetime' => '60',
        'max_lifetime' => '2592000'
    ]
],

Session locking

Por padrão, o session handler do Redis trava a sessão enquanto uma requisição a usa. Duas requisições do mesmo navegador no mesmo instante, por exemplo um carregamento de página mais várias chamadas de customer data sections, esperam uma pela outra. max_concurrency limita quantos processos podem esperar no lock de uma sessão, e break_after_frontend é quantos segundos uma requisição espera antes de quebrar o lock.

Muitas lojas definem disable_locking como 1. O Magento faz muito pouca coisa que dependa de um session locking estrito, e desativar elimina uma classe de requisições lentas que aparecem como esperas aleatórias de vários segundos nos traces de APM. Teste o checkout e as atualizações de carrinho depois de mudar, principalmente se você roda extensões de terceiros que guardam muita coisa na sessão.

Sessões de bots

Crawlers criam uma sessão nova em quase toda requisição. bot_first_lifetime e bot_lifetime dão a essas sessões uma vida bem mais curta, o que evita que o banco de sessões se encha de milhões de chaves que ninguém vai ler de novo.

log_level

Mantenha o log_level baixo em produção. Níveis mais altos escrevem uma linha para muitas operações de sessão e podem gerar muito ruído de log sob carga.

Configuração do servidor Redis

O lado do Magento é só metade da configuração. O servidor Redis precisa da própria configuração, e a linha mais importante é a política de memória.

# Cache instance (port 6379)
maxmemory 2gb
maxmemory-policy allkeys-lru
save ""
appendonly no

# Session instance (port 6380)
maxmemory 1gb
maxmemory-policy noeviction
appendonly yes

Para a instância de cache, allkeys-lru deixa o Redis remover as chaves menos usadas recentemente quando a memória enche. Isso é seguro porque toda entrada de cache pode ser reconstruída. Persistência é trabalho desperdiçado na maior parte do tempo para um cache, então desligar os snapshots RDB e o append only file economiza escrita em disco.

Para sessões, use noeviction e dê memória suficiente à instância. Se ela encher, as escritas falham e você vê erros em vez de perder sessões em silêncio, o que é mais fácil de notar e corrigir. Aqui a persistência é útil, para que um restart do Redis não deslogue todo mundo.

Os tamanhos acima são só exemplos. Meça com redis-cli info memory na sua própria loja e dimensione a partir do used_memory real mais uma folga.

Preload de chaves e o cache L2

Em lojas movimentadas, o tráfego de rede do Redis passa a pesar, porque toda requisição carrega as mesmas entradas de config e EAV. O Magento tem dois recursos para isso.

preload_keys

O backend do Redis aceita uma lista preload_keys em backend_options. Essas chaves são buscadas numa única ida e volta no começo da requisição, em vez de uma por uma. Os nomes das chaves incluem o seu id_prefix, então você as encontra rodando redis-cli monitor no staging durante algumas requisições e escolhendo as chaves carregadas em toda página, como os tipos de entidade do EAV e a lista global de plugins.

Cache em dois níveis

A segunda opção é o backend de cache em dois níveis Magento\Framework\Cache\Backend\RemoteSynchronizedCache. Cada web node mantém uma cópia local dos dados de cache, por exemplo em /dev/shm, e o Redis é usado para verificar se a cópia local ainda está atual:

'default' => [
    'id_prefix' => 'a1b_',
    'backend' => 'Magento\\Framework\\Cache\\Backend\\RemoteSynchronizedCache',
    'backend_options' => [
        'remote_backend' => 'Magento\\Framework\\Cache\\Backend\\Redis',
        'remote_backend_options' => [
            'server' => '10.0.0.5',
            'database' => '0',
            'port' => '6379',
            'compress_data' => '1'
        ],
        'local_backend' => 'Cm_Cache_Backend_File',
        'local_backend_options' => [
            'cache_dir' => '/dev/shm/'
        ],
        'use_stale_cache' => false
    ]
],

Isso ajuda mais quando o Redis fica em outro servidor e a latência de rede se acumula. Num servidor único com o Redis em localhost o ganho é pequeno e você adiciona mais uma peça móvel. Garanta que o diretório local tenha espaço, porque o /dev/shm vive na RAM.

Conferindo se funciona

Algumas checagens rápidas depois da troca:

redis-cli -p 6379 -n 0 dbsize
redis-cli -p 6380 -n 0 dbsize
redis-cli -p 6379 info stats | grep -E 'keyspace_hits|keyspace_misses|evicted_keys'
ls var/cache var/page_cache

A contagem de chaves deve crescer conforme você navega pela loja. As pastas var/cache e var/page_cache devem ficar vazias ou parar de mudar. Se o evicted_keys da instância de sessão estiver acima de zero, tem algo errado na política de memória dela.

Ao limpar o cache, prefira bin/magento cache:clean a cache:flush. O clean remove as entradas com tag do Magento. O flush esvazia todo o storage por trás de cada frontend de cache, o que é aceitável quando o database é dedicado ao cache do Magento, mas destrutivo se mais alguma coisa o compartilha. Nunca aponte um frontend de cache para o database de sessões. Um flush deslogaria todos os clientes.

Problemas comuns

  • Connection refused ou timeouts sob carga: confira o maxclients no lado do Redis e o timeout no env.php. Um Redis lento geralmente está fazendo swap ou dividindo CPU com algo ocupado.
  • Clientes deslogados aleatoriamente: sessões e cache na mesma instância com política de eviction, ou uma instância de sessão que bateu no limite de memória.
  • Requisições lentas com esperas longas na leitura da sessão: session locking. Olhe o waterfall no seu APM e considere desativar o locking.
  • Limpezas de cache que levam minutos: normalmente um número enorme de tags num único database. Separar o page cache do cache padrão ajuda, e mover o full page cache para o Varnish também.

O Redis é uma peça da stack. Para o resto do ajuste do servidor, veja os guias sobre ajuste do PHP-FPM e full page cache com Varnish, e a explicação do env.php e do config.php para as outras seções do arquivo.

FAQ

Sessões e cache do Magento devem usar a mesma instância de Redis?

Funciona, mas uma instância separada para sessões é mais segura. O cache precisa de uma política de eviction e as sessões nunca podem sofrer eviction, e uma instância só pode ter uma política.

Preciso do page cache no Redis se uso Varnish?

Não. Com o Varnish como aplicação de full page cache, o Magento não guarda páginas no frontend page_cache, então você só precisa do Redis para o cache padrão e as sessões.

É seguro desativar o session locking no Magento 2?

Para a maioria das lojas sim, e isso elimina requisições lentas causadas por chamadas paralelas esperando na mesma sessão. Teste carrinho, checkout e qualquer extensão que escreva muito na sessão antes de colocar em produção.

Qual a diferença entre cache:clean e cache:flush com Redis?

O cache:clean remove entradas de cache do Magento por tipo e tag. O cache:flush esvazia o storage por trás dos frontends de cache, então tudo o que mais estiver guardado naquele database do Redis também se perde.

Atendo como freelancer em Magento e Adobe Commerce, incluindo configuração de servidor e cache. Se precisa de ajuda com isso, fale comigo.

Artigos relacionados