+− THE DAILY DIFFdev & AI news
SHIP IT

Shopify a mutat rezervările de inventar în MySQL

Shopify și-a mutat sistemul de rezervare a inventarului de la Redis la baza de date MySQL care deținea deja registrul de inventar.

Shopify și-a mutat sistemul de rezervare a inventarului de la Redis la baza de date MySQL care deținea deja registrul de inventar. Un pool delimitat de rânduri de unități blocabile individual permite checkout-urilor concurente să utilizeze SKIP LOCKED pentru a selecta diferite unități eligibile. Designul depinde, de asemenea, de limitele tranzacțiilor, de structura cheii primare, de regulile de reaprovizionare și de observarea timpului de menținere a conexiunii pe parcursul procesului de checkout.

Citiți ediția scrisă (engleză) ↗

Ce acoperă acest videoclip

  • Vechiul model de contorizare a cantității Redis gestiona concurența, dar curățarea rezervărilor și actualizarea registrului MySQL nu puteau partaja o singură tranzacție atomică locală.
  • Înlocuirea utilizează un rând per unitate disponibilă într-un pool limitat la 1.000 per combinație articol/locație. Un pool gol poate declanșa reaprovizionarea în linie, cu cereri concurente care așteaptă în spatele unei blocări de reaprovizionare.
  • Cheia primară compusă este (shop_id, inventory_item_id, inventory_group_id, id). Shopify a redus cheltuielile generale de blocare în prototipul său și a utilizat READ COMMITTED pentru a evita blocările de spațiu care blocau reaprovizionarea.
  • Rezervarea șterge rândurile pool-ului înainte de a insera înregistrări de rezervare. Comiterea eliberează blocările bazei de date în timp ce blocarea stocată persistă pe parcursul plății; plata reușită revendică registrul și elimină rezervarea într-o tranzacție atomică ulterioară.
  • MySQL documentează SKIP LOCKED ca o vizualizare inconsistentă care omite rândurile blocate. Nu stabilește o numărare completă a stocului sau o preluare echitabilă a rândurilor, se aplică numai blocărilor la nivel de rând și este nesigură pentru replicarea bazată pe declarații.
  • Exemplul sursă include expires_at, dar Shopify nu documentează algoritmul de curățare a expirării MySQL. Ramura de eliberare/expirare a videoclipului este o cerință explicativă a ciclului de viață.
  • Timpul de menținere a conexiunii în alt cod de checkout a fost ultimul blocaj de debit. Shopify a scris în umbră ambele sisteme, a comparat rezultatele și a comutat treptat cu o opțiune de revenire Redis (kill-switch).

Transcrierea tradusă

Tradus din narațiunea originală în engleză. Audio-ul și subtitrările disponibile sunt controlate de YouTube.

De ce să mutați rezervările în MySQL?

0:00 Un checkout are nevoie ca Redis să rămână rapid. Shopify a mutat rezervările de inventar în MySQL folosind un rând per unitate într-un pool delimitat. De ce să alegeți MySQL? Cum să evitați blocările în siguranță? Acesta este The Daily Diff, din culise. Și de ce interogările rapide au atins totuși un plafon? Shopify este o platformă de comerț pentru vânzări online și în persoană. Redis este o bază de date în memorie.

0:21 MySQL este o bază de date relațională, iar Shopify își păstra deja registrul de inventar acolo. O rezervare reține pe scurt stocul în timp ce un cumpărător plătește.

De ce erau riscante două magazine?

0:29 Modelul lor Redis decrementa un contor de articole. Revendicarea unei comenzi plătite însemna actualizarea registrului MySQL și curățarea Redis. Aceste scrieri separate puteau lăsa stocul vândut de două ori sau indisponibil când ar trebui să fie vandabil. Vechiul model nu avea nici conștientizarea locației. Înlocuirea trebuie să aleagă stocul dintr-un loc care poate onora comanda. Un depozit de pe continentul greșit face o intrare excelentă în baza de date și o promisiune teribilă de livrare. Încercările anterioare MySQL au folosit un rând de cantitate, astfel că checkout-urile concurente se puneau la coadă la

Ce devine unitatea blocabilă?

0:56 aceeași blocare. Gândiți-vă la o frânghie de catifea în jurul unei celule de tabel. Adăugarea mai multor lucrători doar prelungește coada. Shopify a schimbat obiectul blocabil. Fiecare unitate disponibilă primește propriul rând. O citire cu blocare omite unitățile pe care o altă tranzacție le deține și selectează alte unități eligibile. Diferiți lucrători pot achiziționa rânduri diferite, în timp ce contorul fierbinte le stă în cale.

Ce se întâmplă când pool-ul se goleşte?

1:15 Acel pool este limitat la o mie de rânduri per articol și locație. Reaprovizionarea se face din registru. Dacă se golește, calea de rezervă se reaprovizionează în linie, cu cereri concurente care așteaptă în spatele unei blocări de reaprovizionare. Pool-ul gol nu înseamnă depozit gol. Rezervarea șterge rândurile selectate din pool, apoi inserează înregistrările de rezervare într-o tranzacție. Comiterea eliberează blocările bazei de date.

1:35 Rollback-ul anulează modificările. Rezervarea supraviețuiește procesării plății ca stare stocată. Plata reușită revendică registrul și elimină rezervarea atomic. Blocările bazei de date nu trebuie niciodată să supravegheze formularul de plată. Cheia lor primară compusă începe cu magazin, articol, grup, apoi identitatea unității. Potrivirea căutării a redus blocarea indexului în prototipul lor. De asemenea, folosesc citire confirmată (read committed) pentru a evita blocările de spațiu care blocau

1:57 reaprovizionarea pool-ului și o ordine consistentă a tabelului pentru a preveni așteptările circulare. Exemplul publicat înregistrează un timp de expirare. Plățile abandonate necesită eliberarea stocului în cele din urmă, altfel coșul de cumpărături devine un proprietar. Postarea Shopify lasă algoritmul de curățare nespecificat, așa că această diagramă arată cerința ciclului de viață. Iată capcana.

Ce omite SKIP LOCKED?

2:14 Skip locked exclude rândurile blocate, așa că manualul numește rezultatul o vizualizare inconsistentă. Nu oferă nici o numărare completă a stocului, nici o preluare echitabilă a rândurilor. Păstrați decizia de disponibilitate și regulile de reaprovizionare în jurul ei.

Unde era adevăratul plafon?

2:26 Și acel plafon? Alt cod de checkout ținea conexiunile la baza de date prea mult timp. Shopify a etichetat apelantii și a măsurat timpul de menținere a conexiunii, apoi a curățat calea de checkout și a revizuit concurența thread-urilor. Interogările rapide pot fi încă în coadă în afara interogării.

De ce aș implementa acest design?

2:38 Au scris în umbră ambele sisteme, cu Redis autoritar, au comparat rezultatele, apoi au comutat treptat cu un kill switch. Verdictul meu este SHIP IT. Aș implementa limita de tranzacție partajată și acea implementare reversibilă (rollbackable rollout), cu întreaga cale de checkout instrumentată. Aveți o întrebare despre asta? Puneți-o în comentarii. Și asta e diferența pentru astăzi.

2:54 Sunt Niko de la Axrisi. Fuzionați responsabil.

Surse

  1. We replaced Redis with MySQL for inventory reservations—and it scaledShopify Engineering — Emilie Noel
  2. Simplified reservation SQL embedded in Shopify's articleShopify Engineering / CourtneySymons on GitHub Gist
  3. MySQL 8.0 — Locking ReadsOracle / MySQL Reference Manual
  4. MySQL 8.0 — Transaction Isolation LevelsOracle / MySQL Reference Manual
  5. What Is Shopify and How Does It Work?Shopify
  6. Redis quick startsRedis documentation
  7. What is MySQL?Oracle / MySQL Reference Manual

Videoclipuri similare