Shopify moveu as reservas de inventário para o MySQL
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.
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.
Ler a edição escrita (Inglês) ↗
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.
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 scaledShopify Engineering — Emilie Noel
- Simplified reservation SQL embedded in Shopify's articleShopify Engineering / CourtneySymons on GitHub Gist
- MySQL 8.0 — Locking ReadsOracle / MySQL Reference Manual
- MySQL 8.0 — Transaction Isolation LevelsOracle / MySQL Reference Manual
- What Is Shopify and How Does It Work?Shopify
- Redis quick startsRedis documentation
- What is MySQL?Oracle / MySQL Reference Manual



