# Shopify moveu reservas de estoque para o MySQL

Published: 2026-10-10

A Shopify moveu seu sistema de reserva de estoque do Redis para o banco de dados MySQL que já mantinha o livro-razão de estoque. Um pool limitado de linhas de unidades individualmente bloqueáveis permite que checkouts concorrentes usem SKIP LOCKED para selecionar diferentes unidades elegíveis. O design também depende dos limites da transação, layout da chave primária, regras de reabastecimento e observação do tempo de espera da conexão durante o checkout.

Canonical: https://thedailydiff.dev/pt-BR/video/shopify-reservation-locks/

## O que este vídeo aborda

- O antigo modelo de contador de quantidade do Redis lidava com a concorrência, mas a limpeza da reserva e a atualização do livro-razão do MySQL não podiam compartilhar uma única transação atômica local.
- A substituição usa uma linha por unidade disponível em um pool limitado a 1.000 por combinação item/local. Um pool vazio pode acionar o reabastecimento em linha com solicitações concorrentes esperando atrás de um bloqueio de reabastecimento.
- A chave primária composta é (shop\_id, inventory\_item\_id, inventory\_group\_id, id). A Shopify reduziu a sobrecarga de bloqueio em seu protótipo e usou READ COMMITTED para evitar bloqueios de lacuna que impediam o reabastecimento.
- A reserva exclui linhas do pool antes de inserir registros de reserva. A confirmação libera os bloqueios do banco de dados enquanto a retenção armazenada persiste durante o pagamento; o pagamento bem-sucedido reivindica o livro-razão e remove a reserva em uma transação atômica posterior.
- O MySQL documenta SKIP LOCKED como uma visão inconsistente que omite linhas bloqueadas. Não estabelece uma contagem de estoque completa ou turnos justos, aplica-se apenas a bloqueios de nível de linha e é inseguro para replicação baseada em declaração.
- O exemplo de origem inclui expires\_at, mas a Shopify não documenta o algoritmo de limpeza de expiração do MySQL. A ramificação de liberação/expiração do vídeo é um requisito de ciclo de vida explicativo.
- O tempo de espera da conexão em outro código de checkout foi o gargalo final de throughput. A Shopify escreveu em sombra ambos os sistemas, comparou os resultados e mudou gradualmente com um fallback de "kill-switch" do Redis.

## Capítulos

- 0:00 Por que mover as reservas para o MySQL?
- 0:29 Por que duas lojas eram arriscadas?
- 0:52 O que se torna a unidade bloqueável?
- 1:15 O que acontece quando o pool se esvazia?
- 2:14 O que o SKIP LOCKED deixa de fora?
- 2:26 Onde estava o verdadeiro teto?
- 2:38 Por que eu enviaria este projeto?

## Transcrição traduzida

Traduzido da narração original em inglês. Áudio e legendas disponíveis são controlados pelo YouTube.

### Por que mover as reservas para o MySQL?

0:00 Um checkout precisa do Redis para se manter rápido. A Shopify moveu as reservas de estoque para o MySQL usando uma linha por unidade em um pool limitado. Por que escolher o MySQL? Como pular bloqueios com segurança? Este é o The Daily Diff, por trás das cenas. E por que as consultas rápidas ainda atingiram um teto? Shopify é uma plataforma de comércio para vender online e presencialmente. Redis é um armazenamento de dados em memória.

0:21 MySQL é um banco de dados relacional, e a Shopify já mantinha seu livro-razão de estoque lá. Uma reserva retém brevemente o estoque enquanto o comprador paga.

### Por que duas lojas eram arriscadas?

0:29 O modelo Redis deles decrementava um contador de itens. Reivindicar um pedido pago significava atualizar o livro-razão do MySQL e limpar o Redis. Essas gravações separadas podiam deixar o estoque vendido duas vezes ou indisponível quando deveria estar disponível para venda. O modelo antigo também não tinha consciência de localização. A substituição deve escolher o estoque de algum lugar que possa atender ao pedido. Um armazém no continente errado é uma excelente entrada de banco de dados e uma péssima promessa de entrega. Tentativas anteriores no MySQL usavam uma linha de quantidade, então checkouts concorrentes faziam fila no

### O que se torna a unidade bloqueável?

0:56 mesmo bloqueio. Pense em uma corda de veludo em torno de uma célula de planilha. Adicionar mais trabalhadores apenas alonga a fila. A Shopify mudou o objeto bloqueável. Cada unidade disponível recebe sua própria linha. Uma leitura de bloqueio pula unidades que outra transação mantém e seleciona outras unidades elegíveis. Diferentes trabalhadores podem adquirir diferentes linhas, enquanto o contador quente fica fora do caminho deles.

### O que acontece quando o pool se esvazia?

1:15 Esse pool é limitado a mil linhas por item e localização. O reabastecimento é feito a partir do livro-razão. Se esvaziar, o caminho de reserva reabastece em linha, com solicitações concorrentes esperando atrás de um bloqueio de reabastecimento. Pool vazio não significa armazém vazio. A reserva exclui as linhas do pool selecionadas e, em seguida, insere os registros de reserva em uma transação. O commit libera os bloqueios do banco de dados.

1:35 O rollback desfaz as alterações. A reserva sobrevive ao processamento do pagamento como estado armazenado. O pagamento bem-sucedido reivindica o livro-razão e remove a reserva atomicamente. Os bloqueios do banco de dados nunca precisam "cuidar" do formulário de pagamento. Sua chave primária composta começa com loja, item, grupo e depois identidade da unidade. Corresponder à pesquisa reduziu o bloqueio de índice em seu protótipo. Eles também usam "read committed" para evitar os bloqueios de lacuna que bloqueavam o reabastecimento

1:57 do pool, e uma ordem de tabela consistente para evitar esperas circulares. O exemplo publicado registra um tempo de expiração. Pagamentos abandonados precisam que o estoque seja liberado eventualmente, ou o carrinho de compras se torna um senhorio. A postagem da Shopify deixa esse algoritmo de limpeza não especificado, então este diagrama mostra o requisito do ciclo de vida. Aqui está a pegadinha.

### O que o SKIP LOCKED deixa de fora?

2:14 Skip locked exclui linhas bloqueadas, então o manual chama seu resultado de "visão inconsistente". Não fornece uma contagem de estoque completa nem turnos justos. Mantenha a decisão de disponibilidade e as regras de reabastecimento em torno dela.

### Onde estava o verdadeiro teto?

2:26 E aquele teto? Outro código de checkout estava mantendo as conexões do banco de dados por muito tempo. A Shopify marcou os chamadores e mediu o tempo de retenção da conexão, depois limpou o caminho de checkout e revisitou a concorrência de threads. Consultas rápidas ainda podem fazer fila fora da consulta.

### Por que eu enviaria este projeto?

2:38 Eles escreveram em sombra ambos os sistemas com o Redis como autoritário, compararam os resultados e, em seguida, mudaram gradualmente com um "kill switch" (chave de interrupção). Meu veredito é SHIP IT. Eu enviaria o limite de transação compartilhado e essa implementação com rollback, com todo o caminho de checkout instrumentado. Tem alguma pergunta sobre isso? Coloque nos comentários. E esse é o "diff" de hoje.

2:54 Sou Niko da Axrisi. Mescle com responsabilidade.

## Fontes

- [We replaced Redis with MySQL for inventory reservations—and it scaled](https://shopify.engineering/scaling-inventory-reservations) — Shopify Engineering — Emilie Noel
- [Simplified reservation SQL embedded in Shopify's article](https://gist.github.com/CourtneySymons/cb5ecbe86331047aae166d5b1f1d555c) — Shopify Engineering / CourtneySymons on GitHub Gist
- [MySQL 8.0 — Locking Reads](https://dev.mysql.com/doc/refman/8.0/en/innodb-locking-reads.html) — Oracle / MySQL Reference Manual
- [MySQL 8.0 — Transaction Isolation Levels](https://dev.mysql.com/doc/refman/8.0/en/innodb-transaction-isolation-levels.html) — Oracle / MySQL Reference Manual
- [What Is Shopify and How Does It Work?](https://www.shopify.com/blog/what-is-shopify) — Shopify
- [Redis quick starts](https://redis.io/docs/latest/develop/get-started/) — Redis documentation
- [What is MySQL?](https://dev.mysql.com/doc/refman/8.0/en/what-is-mysql.html) — Oracle / MySQL Reference Manual
