# Shopify moveu as reservas de inventário para o MySQL

Published: 2026-10-10

A Shopify moveu o seu sistema de reserva de inventário do Redis para a base de dados MySQL que já continha o livro de inventário. Um conjunto limitado de linhas de unidades bloqueáveis individualmente permite que checkouts concorrentes utilizem SKIP LOCKED para selecionar diferentes unidades elegíveis. O design também depende dos limites de 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-PT/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 MySQL não podiam partilhar uma única transação atómica local.
- A substituição utiliza uma linha por unidade disponível num conjunto limitado a 1.000 por combinação de item/localização. Um conjunto vazio pode acionar o reabastecimento em linha com pedidos concorrentes a aguardar por trá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 no seu protótipo e utilizou READ COMMITTED para evitar bloqueios de lacunas que bloqueavam o reabastecimento.
- A reserva elimina as linhas do conjunto antes de inserir os registos de reserva. A confirmação liberta os bloqueios da base de dados enquanto a retenção armazenada persiste durante o pagamento; o pagamento bem-sucedido reivindica o livro-razão e remove a reserva numa transação atómica posterior.
- O MySQL documenta SKIP LOCKED como uma vista inconsistente que omite as linhas bloqueadas. Não estabelece uma contagem de stock completa ou uma vez justa, aplica-se apenas a bloqueios ao nível da linha e não é seguro para replicação baseada em declarações.
- O exemplo de origem inclui expires\_at, mas a Shopify não documenta o algoritmo de limpeza de expiração do MySQL. O ramo 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 resultados e alternou gradualmente com um fallback de "kill-switch" do Redis.

## Capítulos

- 0:00 Porquê 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 conjunto fica vazio?
- 2:14 O que o SKIP LOCKED deixa de fora?
- 2:26 Onde estava o verdadeiro limite?
- 2:38 Por que eu enviaria este design?

## Transcrição traduzida

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

### Porquê mover as reservas para o MySQL?

0:00 Um checkout precisa do Redis para se manter rápido. A Shopify moveu as reservas de inventário para o MySQL usando uma linha por unidade num conjunto limitado. Porquê escolher o MySQL? Como ignorar bloqueios com segurança? Este é o The Daily Diff, nos bastidores. E por que as consultas rápidas ainda atingiam um limite? A Shopify é uma plataforma de comércio para vender online e presencialmente. Redis é um armazenamento de dados em memória.

0:21 MySQL é uma base de dados relacional, e a Shopify já mantinha o seu livro-razão de inventário lá. Uma reserva detém brevemente o stock enquanto um comprador paga.

### Por que duas lojas eram arriscadas?

0:29 O seu modelo Redis decrementava um contador de itens. Reivindicar um pedido pago significava atualizar o livro-razão MySQL e limpar o Redis. Essas escritas separadas podiam deixar o stock vendido duas vezes ou indisponível quando deveria estar vendável. O modelo antigo também não tinha consciência de localização. A substituição deve escolher o stock de um local que possa satisfazer o pedido. Um armazém no continente errado faz uma excelente entrada de base de dados e uma terrível promessa de entrega. Tentativas anteriores de MySQL usavam uma linha de quantidade, então os checkouts concorrentes enfileiravam-se no

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

0:56 mesmo bloqueio. Pense numa corda de veludo em volta de uma célula de folha de cálculo. Adicionar mais trabalhadores apenas alonga a fila. A Shopify alterou o objeto bloqueável. Cada unidade disponível tem a sua própria linha. Uma leitura de bloqueio ignora unidades que outra transação deté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 conjunto fica vazio?

1:15 Esse conjunto é 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 pedidos concorrentes a aguardar por trás de um bloqueio de reabastecimento. Conjunto vazio não significa armazém vazio. A reserva elimina as linhas do conjunto selecionadas, depois insere registos de reserva numa transação. O commit liberta os bloqueios da base 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 da base de dados nunca precisam de controlar o formulário de pagamento. A sua chave primária composta começa com loja, item, grupo, depois identidade da unidade. Corresponder à pesquisa reduziu o bloqueio de índice no seu protótipo. Eles também usam "read committed" para evitar os bloqueios de lacuna que bloqueavam o

1:57 reabastecimento do pool, e uma ordem de tabela consistente para evitar esperas circulares. O exemplo publicado regista um tempo de expiração. Pagamentos abandonados precisam que o stock seja libertado eventualmente, ou o carrinho de compras torna-se um senhorio. A publicação da Shopify deixa esse algoritmo de limpeza não especificado, portanto este diagrama mostra o requisito do ciclo de vida. Aqui está o problema.

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

2:14 Ignorar linhas bloqueadas exclui as linhas bloqueadas, então o manual chama o seu resultado de uma visão inconsistente. Não fornece uma contagem de stock completa nem uma vez justa. Mantenha a decisão de disponibilidade e as regras de reabastecimento à sua volta.

### Onde estava o verdadeiro limite?

2:26 E esse limite? Outro código de checkout estava a manter as conexões da base de dados por muito tempo. A Shopify marcou os chamadores e mediu o tempo de espera da conexão, depois limpou o caminho de checkout e revisitou a concorrência de threads. Consultas rápidas ainda podem enfileirar fora da consulta.

### Por que eu enviaria este design?

2:38 Eles escreveram em sombra ambos os sistemas com o Redis como autoritativo, compararam os resultados e depois mudaram gradualmente com um kill switch. O meu veredito é SHIP IT. Eu SHIP IT o limite de transação partilhada e essa implementação com rollback, com todo o caminho de checkout instrumentado. Tem alguma pergunta sobre isto? Coloque-a nos comentários. E essa é a diferença de hoje.

2:54 Eu sou o Niko da Axrisi. Mesclar 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
