O que é a troca do Redis pelo MySQL no Shopify

O Shopify e uma das maiores plataformas de e-commerce do mundo, processando bilhoes de dólares em vendas - especialmente em eventos como Black Friday e Cyber Monday. Para suportar esse volume, a engenharia deles precisa ser impecável em cada detalhe.

Em 2024, a equipe de engenharia do Shopify tomou uma decisão que surpreendeu muita gente: substituir o Redis pelo MySQL para gerenciar as reservas de estoque. O Redis e famoso por ser um banco em memoria, extremamente rápido para operações de leitura e escrita. Usar MySQL no lugar parecia ir contra o senso comum.

O resultado? A migração funcionou muito bem. A plataforma escalou melhor, ficou mais simples de operar e o time de engenharia ganhou mais confiança no sistema. A historia virou caso de estudo sobre como a escolha certa de tecnologia nem sempre e a mais óbvia.

Como funciona o sistema de reservas de estoque

Quando você adiciona um produto ao carrinho numa loja Shopify, o sistema precisa reservar temporariamente aquele item. Isso evita que dois clientes comprem o mesmo produto ao mesmo tempo. E uma operação crítica: falhar aqui significa vender o que não existe no estoque.

Com Redis, as reservas eram guardadas como entradas temporárias em memoria com tempo de expiração (TTL). E uma abordagem clássica para esse tipo de problema - rápida e sem overhead de disco. O problema e que o Redis exigia sincronização cuidadosa com o banco principal (MySQL), e qualquer falha de rede ou reinicialização do Redis podia causar inconsistências.

Com MySQL, a equipe modelou as reservas como linhas em uma tabela com transações ACID. A consistência passa a ser garantida pelo próprio banco. O MySQL já estava rodando em produção, já tinha backups, monitoramento, equipe experiente e anos de ajuste de performance. Não havia necessidade de operar um segundo sistema separado.

💡
Dica

O grande insight do Shopify foi perceber que o gargalo não era a velocidade bruta do banco - era a complexidade operacional de manter dois sistemas de persistência sincronizados em tempo real.

Principais vantagens da abordagem com MySQL

A migração trouxe ganhos em varias frentes que a equipe do Shopify detalhou publicamente:

  • Consistência transacional: transações ACID garantem que uma reserva nunca fica em estado intermediário. Ou ela existe, ou não existe.
  • Menos surface área operacional: uma tecnologia a menos para monitorar, fazer backup, ajustar em produção e treinar novos engenheiros.
  • Queries complexas de graça: com SQL você faz JOINs, agregações e análises diretamente. No Redis, isso exigiria código adicional na aplicação.
  • Durabilidade nativa: dados em MySQL sobrevivem a reinicializações e falhas de servidor sem nenhuma configuração extra.
  • Melhor debugabilidade: inspecionar o estado das reservas via SELECT e muito mais simples do que navegar em estruturas do Redis.

O ponto central e que o Redis foi criado para casos onde você precisa de velocidade extrema em operações simples. Mas as reservas de estoque do Shopify não eram tao simples assim - elas envolviam lógica de negócio complexa que se encaixava melhor no modelo relacional.

⚠️
Atenção

Isso não significa que Redis e ruim. Significa que Redis foi escolhido originalmente por um motivo que, com o tempo, ficou menos relevante do que a consistência e a simplicidade operacional.

Como começar: modelando reservas de estoque com MySQL

Se você quiser aplicar um padrão similar em seus projetos, a estrutura básica de uma tabela de reservas em MySQL ficaria assim:

CREATE TABLE inventory_reservations (
  id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  product_variant_id BIGINT UNSIGNED NOT NULL,
  quantity INT NOT NULL,
  cart_token VARCHAR(255) NOT NULL,
  reserved_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  expires_at DATETIME NOT NULL,
  ÍNDEX idx_variant (product_variant_id),
  ÍNDEX idx_cart (cart_token),
  ÍNDEX idx_expires (expires_at)
);

Para reservar um item, você usa uma transação que primeiro verifica o estoque disponível e depois insere a reserva atomicamente. Isso garante que não ha condição de corrida entre dois pedidos simultâneos.

START TRANSACTION;

-- Verifica estoque disponível
SELECT available_quantity INTO @available
FROM inventory
WHERE product_variant_id = 123
FOR UPDATE;

-- Só reserva se tiver quantidade suficiente
IF @available >= 1 THEN
  INSERT INTO inventory_reservations
    (product_variant_id, quantity, cart_token, expires_at)
  VALUES (123, 1, 'abc-cart-token', NOW() + INTERVAL 30 MINUTE);
END IF;

COMMIT;

Um job periódico limpa reservas expiradas. Isso e mais previsível e auditavel do que depender de TTLs do Redis.

Exemplo prático: simulando o fluxo de checkout

Imagine uma loja com 5 unidades de um ténis limitado. Dois usuários tentam comprar ao mesmo tempo no Black Friday. Com MySQL e transações, o fluxo fica assim:

Usuário A inicia transação, le 5 unidades disponível, insere reserva de 1 unidade, faz commit. Agora ha 4 disponíveis e 1 reservada. Usuário B inicia transação, le o estado atual (4 disponíveis, pois o FOR UPDATE bloqueia concorrentemente), insere reserva de 1 unidade, faz commit. Ambas as reservas existem sem conflito.

-- Verificar estado das reservas ativas
SELECT
  p.name AS produto,
  COUNT(r.id) AS reservas_ativas,
  SUM(r.quantity) AS unidades_reservadas
FROM inventory_reservations r
JOIN products p ON r.product_variant_id = p.id
WHERE r.expires_at > NOW()
GROUP BY p.id, p.name;

Essa query de auditoria e trivial em SQL. No Redis, você precisaria de lógica extra na aplicação para montar o mesmo relatório.

🚀
Pro tip

Adicione um índex em expires_at e rode um job de limpeza a cada 5 minutos com DELETE WHERE expires_at < NOW(). Isso mantem a tabela enxuta sem impactar o desempenho das queries de reserva.

Comparação com alternativas

Existem varias abordagens para o problema de reservas de estoque em sistemas de alta demanda. Cada uma tem seu espaço:

  • Redis puro: excelente para casos onde velocidade e tudo e a perda de dados em falha e tolerável. Caches de sessão, filas de tarefas, rate limiting. Para reservas financeiras com consistência obrigatória, arriscado sem configuração cuidadosa.
  • MySQL (abordagem Shopify): melhor quando você já tem MySQL em produção, precisa de consistência ACID, e a latência extra de microsegundos não e crítica. Simplifica operações dramaticamente.
  • PostgreSQL: alternativa robusta ao MySQL com recursos avançados como SELECT FOR UPDATE SKIP LOCKED, ótimo para filas e reservas. Igualmente valido para esse padrão.
  • Combinação Redis + MySQL: a abordagem original do Shopify. Mais complexa de operar, mas pode fazer sentido se você precisar de caching agressivo em cima da consistência.

A licao e que não existe bala de prata. O Shopify escolheu MySQL porque ele resolvia todos os requisitos deles sem adicionar complexidade desnecessária.

Pontos positivos e limitações

A abordagem com MySQL tem forcas reais em produção: operabilidade simples, consistência garantida, equipes já familiarizadas, ferramentas de monitoramento maduras. O Shopify reportou menos incidentes relacionados a sincronização após a migração.

As limitações também existem. Se você tiver cargas de escrita extremamente altas (centenas de milhares de reservas por segundo), o MySQL pode atingir seus limites antes do Redis. Para casos assim, você precisaria de sharding, proxies de banco ou uma abordagem diferente.

🔴
Cuidado

Não migre um sistema Redis funcionando só porque o Shopify migrou. Avalie seus requisitos específicos: volume de escrita, tolerância a falhas, consistência necessária. A decisão do Shopify faz sentido para o contexto deles.

Outro ponto: o MySQL precisa de índices bem configurados para performar bem com muitas reservas simultâneas. Um índex esquecido em expires_at pode causar table scans caros durante a limpeza das reservas expiradas.

Casos de uso reais

Esse padrão se aplica muito bem em algumas situações específicas do mundo real:

  • E-commerce com estoque limitado: produtos de edição limitada, ingressos, vagas em cursos. Qualquer situação onde múltiplos usuários podem tentar comprar o mesmo item simultaneamente e a consistência e crítica.
  • Sistemas de agendamento: reserva de horários em clínicas, salas de reunião, slots de entrega. O modelo de reserva temporária com expiração e idêntico ao do e-commerce.
  • Plataformas de licitação: reserva de créditos ou garantias durante um lance. Você precisa garantir atomicidade e auditabilidade.
  • SaaS com uso metered: reservar cota de API durante uma requisição para evitar ultrapassar limites. MySQL com transações oferece consistência necessária.

Dicas e boas práticas

💡
Dica

Defina um tempo de expiração conservador para as reservas (15 a 30 minutos para e-commerce). Muito curto frustra o usuário no checkout; muito longo trava estoque desnecessariamente.

💡
Dica

Use SELECT ... FOR UPDATE ao verificar estoque antes de inserir a reserva. Isso garante exclusão mutua sem precisar de locks manuais ou lógica de retry na aplicação.

⚠️
Atenção

Monitore o tempo médio de transação. Transações longas seguram locks e podem causar timeouts em cascata durante picos de tráfego. Mantenha a lógica dentro da transação mínima e necessária.

🚀
Pro tip

Considere uma tabela separada de reservas em vez de coluna de status no produto. Isso facilita queries de auditoria, histórico e debug sem impactar a tabela principal de inventario.

Vale a pena?

A decisão do Shopify de trocar Redis por MySQL e um estudo de caso poderoso sobre complexidade acidental. Redis foi adicionado porque parecia a escolha óbvia para operações rápidas. Com o tempo, a complexidade de manter dois sistemas sincronizados custava mais do que o beneficio de velocidade.

Para a maioria dos projetos brasileiros de e-commerce, SaaS ou sistemas com reservas, o MySQL (ou PostgreSQL) com transações ACID e a escolha mais solida. Você ganha consistência, operabilidade, ferramentas maduras e uma equipe que já sabe operar o sistema.

Use Redis quando você tem um problema específico que ele resolve melhor: cache de leitura agressivo, filas de tarefas, pub/sub, rate limiting. Não use só porque e mais rápido em benchmarks sintéticos - operações reais em produção tem outros gargalos.