Shopify a déplacé les réservations d'inventaire vers MySQL
Shopify a déplacé son système de réservation d'inventaire de Redis vers la base de données MySQL qui contenait déjà le registre d'inventaire.
Shopify a déplacé son système de réservation d'inventaire de Redis vers la base de données MySQL qui contenait déjà le registre d'inventaire. Un pool borné de lignes d'unités individuellement verrouillables permet aux paiements concurrents d'utiliser SKIP LOCKED pour sélectionner différentes unités éligibles. La conception dépend également des limites de transaction, de la disposition de la clé primaire, des règles de réapprovisionnement et de l'observation du temps de maintien de la connexion lors du paiement.
Lire l'édition écrite (anglais) ↗
Ce que couvre cette vidéo
- L'ancien modèle de compteur de quantité Redis gérait la concurrence, mais le nettoyage des réservations et la mise à jour du registre MySQL ne pouvaient pas partager une seule transaction atomique locale.
- Le remplacement utilise une ligne par unité disponible dans un pool plafonné à 1 000 par combinaison article/emplacement. Un pool vide peut déclencher un réapprovisionnement en ligne avec des requêtes concurrentes en attente derrière un verrou de réapprovisionnement.
- La clé primaire composite est (shop_id, inventory_item_id, inventory_group_id, id). Shopify a réduit la surcharge de verrouillage dans son prototype et a utilisé READ COMMITTED pour éviter les verrous d'intervalle qui bloquaient le réapprovisionnement.
- La réservation supprime les lignes du pool avant d'insérer des enregistrements de réservation. La validation libère les verrous de la base de données tandis que la retenue stockée persiste pendant le paiement ; un paiement réussi réclame le registre et supprime la réservation dans une transaction atomique ultérieure.
- MySQL documente SKIP LOCKED comme une vue incohérente qui omet les lignes verrouillées. Il n'établit pas un compte de stock complet ni un tour de rôle équitable, ne s'applique qu'aux verrous au niveau de la ligne et n'est pas sûr pour la réplication basée sur les instructions.
- L'exemple source inclut expires_at, mais Shopify ne documente pas l'algorithme de nettoyage d'expiration MySQL. La branche de libération/expiration de la vidéo est une exigence de cycle de vie explicative.
- Le temps de maintien de la connexion dans d'autres codes de paiement était le dernier goulot d'étranglement du débit. Shopify a effectué des écritures fantômes sur les deux systèmes, a comparé les résultats et a basculé progressivement avec un mécanisme de secours "kill-switch" Redis.
Transcription traduite
Traduit de la narration originale en anglais. L'audio et les sous-titres disponibles sont gérés par YouTube.
Pourquoi déplacer les réservations dans MySQL ?
0:00 Un paiement nécessite que Redis reste rapide. Shopify a déplacé les réservations d'inventaire dans MySQL en utilisant une ligne par unité dans un pool borné. Pourquoi choisir MySQL ? Comment ignorer les verrous en toute sécurité ? Ceci est The Daily Diff, dans les coulisses. Et pourquoi les requêtes rapides atteignaient-elles encore un plafond ? Shopify est une plateforme de commerce pour vendre en ligne et en personne. Redis est un magasin de données en mémoire.
0:21 MySQL est une base de données relationnelle, et Shopify y conservait déjà son registre d'inventaire. Une réservation retient brièvement le stock pendant qu'un acheteur paie.
Pourquoi deux magasins étaient-ils risqués ?
0:29 Leur modèle Redis décrémentait un compteur d'articles. Réclamer une commande payée signifiait mettre à jour le registre MySQL et nettoyer Redis. Ces écritures séparées pouvaient laisser du stock vendu deux fois ou indisponible alors qu'il devrait être vendable. L'ancien modèle manquait également de connaissance de l'emplacement. Le remplacement doit choisir le stock d'un endroit qui peut exécuter la commande. Un entrepôt sur le mauvais continent fait une excellente entrée de base de données et une terrible promesse de livraison. Les tentatives antérieures de MySQL utilisaient une ligne de quantité, de sorte que les paiements concurrents faisaient la queue au
Quelle devient l'unité verrouillable ?
0:56 même verrou. Imaginez un cordon de velours autour d'une cellule de feuille de calcul. Ajouter plus de travailleurs ne fait qu'allonger la file d'attente. Shopify a changé l'objet verrouillable. Chaque unité disponible obtient sa propre ligne. Une lecture de verrouillage ignore les unités qu'une autre transaction détient et sélectionne d'autres unités éligibles. Différents travailleurs peuvent acquérir différentes lignes, tandis que le compteur chaud reste en dehors de leur chemin.
Que se passe-t-il lorsque le pool se vide ?
1:15 Ce pool est borné à mille lignes par article et emplacement. Le réapprovisionnement est tiré du registre. S'il se vide, le chemin de réservation se réapprovisionne en ligne, avec des requêtes concurrentes en attente derrière un verrou de réapprovisionnement. Pool vide ne signifie pas entrepôt vide. La réservation supprime les lignes de pool sélectionnées, puis insère les enregistrements de réservation dans une transaction. La validation libère les verrous de la base de données.
1:35 La restauration annule les modifications. La réservation survit au traitement du paiement en tant qu'état stocké. Un paiement réussi réclame le registre et supprime la réservation de manière atomique. Les verrous de la base de données n'ont jamais besoin de surveiller le formulaire de paiement. Leur clé primaire composite commence par le magasin, l'article, le groupe, puis l'identité de l'unité. La correspondance de la recherche a réduit le verrouillage de l'index dans leur prototype. Ils utilisent également la lecture validée pour éviter les verrous d'intervalle qui bloquaient le réapprovisionnement du pool,
1:57 et un ordre de table cohérent pour éviter les attentes circulaires. L'exemple publié enregistre une heure d'expiration. Les paiements abandonnés nécessitent que le stock soit éventuellement libéré, ou le panier d'achat devient un propriétaire. Le message de Shopify ne précise pas cet algorithme de nettoyage, ce diagramme montre donc l'exigence du cycle de vie. Voici le piège.
Qu'est-ce que SKIP LOCKED omet ?
2:14 Skip locked exclut les lignes verrouillées, le manuel appelle donc son résultat une vue incohérente. Il ne fournit ni un compte de stock complet ni une prise de tour équitable. Gardez la décision de disponibilité et les règles de réapprovisionnement autour de cela.
Où était le vrai plafond ?
2:26 Et ce plafond ? D'autres codes de paiement maintenaient les connexions à la base de données trop longtemps. Shopify a étiqueté les appelants et mesuré le temps de maintien de la connexion, puis a nettoyé le chemin de paiement et a revu la concurrence des threads. Les requêtes rapides peuvent encore être mises en file d'attente en dehors de la requête.
Pourquoi expédier cette conception ?
2:38 Ils ont effectué des écritures fantômes sur les deux systèmes, avec Redis faisant autorité, ont comparé les résultats, puis ont basculé progressivement avec un interrupteur d'arrêt. Mon verdict est SHIP IT. Je livrerais la limite de transaction partagée et ce déploiement réversible, avec tout le chemin de paiement instrumenté. Vous avez une question à ce sujet ? Mettez-la dans les commentaires. Et c'est le "diff" pour aujourd'hui.
2:54 Je suis Niko d'Axrisi. Fusionnez de manière responsable.
Sources
- 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



