deniz.in

Piyasalar

Hava durumu

Hava durumu yükleniyor

· kaynak dev.to (home feed)

Shopify, Redis'teki stok rezervasyonlarını MySQL'e taşıdı: birim başına bir satır ve SKIP LOCKED ile

Shopify, ödeme adımındaki stok rezervasyonlarını Redis'teki bir sayaçtan MySQL'e taşıdı; her uygun birim kendi satırına sahip olduğu için eşzamanlı ödeme işlemleri SKIP LOCKED sayesinde farklı birimleri kilitleyebiliyor.

Shopify, Redis'teki stok rezervasyonlarını MySQL'e taşıdı: birim başına bir satır ve SKIP LOCKED ile

Ödeme akışındaki iki an

Shopify'nin mühendislik ekibi, bir dev.to yazısında özetlendiği üzere, rezervasyonu iki ayrı ana ayırıyor. Reserve (rezerve etme), müşteri ödemeye başladığında başlar ve geçici bir hold oluşturur. Claim (talep etme), ödeme başarılı olduktan sonra gerçekleşir ve birimleri defterden kalıcı olarak düşer; defter doğru kaynağın kendisi olarak kalır. Ödeme zaman alır ve bu aralıkta başka hiçbir ödeme işlemi tutulan birimi satamamalıdır — ancak yarım bırakılmış bir deneme, stoğunu eninde sonunda serbest bırakmalıdır.

Önceki tasarım rezervasyon durumunu Redis'te, ürün başına bir miktar sayacı olarak tutuyordu: azaltmak bir birimi rezerve ediyor, artırmak serbest bırakıyordu. dev.to yazısına göre Redis eşzamanlılığı kendi başına yeterince yönetiyordu; zor sınır, rezervasyon ile defter arasındaydı. Ödenmiş bir sipariş MySQL'i güncelliyor ve Redis'i ayrı yazışmalarla temizliyordu; aralarındaki bir kesinti stoğun fazla satılmasına ya da satılamaz durumda mahsur kalmasına yol açabilirdi. Sayaç ayrıca konumdan habersizdi; oysa bir birim, yalnızca siparişi karşılayabilecek bir konumdan geliyorsa işe yarar.

Sınırlı bir havuz içinde, birim başına bir satır

Shopify daha önce tek bir miktar satırı kullanarak MySQL rezervasyonları denemişti; bu, kilit bir noktaya dönüşmüştü: rekabet eden ödeme işlemleri aynı satırda kuyruk oluyordu ve worker eklemek yalnızca orada bekleyen isteklerin artması anlamına geliyordu. Yeni tasarım bağımsız olarak kilitlenebilir nesneyi değiştiriyor. Her uygun birim, uygun havuzda kendi satırına sahip oluyor ve bir rezervasyon ihtiyacı olan satırları seçiyor; böylece eşzamanlı transaction'lar paylaşılan bir sayaç için kavga etmek yerine ayrı birimleri edinebiliyor.

Şemayı pratik tutmak için havuz, ürün ve konum kombinasyonu başına 1.000 satırla sınırlıdır. Bu üst sınır temsilciyi sınırlar, satıcının gerçek stoğunu değil: defter, etkin havuzun ötesindeki stenvanteri tanımlayabilir ve ikmal gerektikçe birimleri içeri getirir. Normal ikmal arka planda bir süreç tarafından yürütülür; havuzun boşaldığı an içinse bir inline yol vardır — bu yol bir kilit alır, böylece aynı ürün için rekabet eden istekler beklerken işi yalnızca bir ikmalci yapar.

SKIP LOCKED neyi garanti eder, neyi etmez

MySQL'nin locking-read dokümantasyonu SKIP LOCKED'u şöyle tanımlar: kilitleme okuması, hemen edinemediği kilitlere sahip satırları hariç tutar ve beklemek yerine diğer satırları döndürür. Aynı havuzdan seçim yapan iki worker etkisini gösterir — biri bir birimin satırını tutar, diğeri onu baypas eder ve farklı bir kilitlenmemiş birimi alır.

Uyarılar mekanizma kadar önemlidir. MySQL, kilitli satırları atlayan sorguların tutarsız bir görünüm döndürdüğü konusunda uyarır; dolayısıyla boş bir sonuç, stoğun tükendiğini kanıtlayamaz: satırlar başka transaction'lar tarafından tutuluyor olabilir ya da havuzun yalnızca ikmale ihtiyacı olabilir. Belgelenmiş bir adalet veya FIFO garantisi yoktur ve kılavuz bu ifadeleri statement-based replication için güvensiz olarak işaretler. Erişilebilirlik kararından, veritabanı değil, çevresindeki uygulama sorumlu olmaya devam eder.

Kısa transaction'lar hold'u ödeme boyunca taşır

Shopify'nin yayımladığı akışta reserve, seçilen havuz satırlarını siler ve rezervasyon kayıtlarını tek bir transaction içinde ekler. Commit, veritabanı kilitlerini serbest bırakır ve saklı rezervasyon, müşteri ödemeyi tamamlarken kalıcı olur. Ödeme başarılı olduktan sonra claim, defteri günceller ve ilgili rezervasyonu atomik olarak kaldırır — her iki işlem de MySQL içinde yaşar, dolayısıyla tek bir yerel transaction yeterlidir. Müşterinin ödeme formuyla etkileşimi boyunca hiçbir satır kilidi tutulmaz.

dev.to yazısı, yayımlanan örnekteki bir tuzağa dikkat çeker: gömülü SQL farklı tablo adları kullanır ve ekleme işleminden önce silme gösterir; kapanış metni ise sırayı düzelterek önce reservation_units tablosundan silinip sonra reserved_quantities tablosuna ekleme yapılması gerektiğini belirtir. Süre sonlandırma da benzer şekilde açık bırakılmıştır — örnek bir expires_at alanı içerir ve hold'lerin birkaç dakika sürdüğünü açıklar; ancak temizlik algoritması, iptal yönetimi, retry politikası ve geç ödeme başarısı davranışı belirsizdir. Yazı ayrıca, rezervasyon sorgularının kendisi hızlı olsa bile, ödeme akışının başka yerlerindeki bağlantı tutma süresinin bir ölçekleme kısıtı haline geldiğini belirtir.

Neden önemli

Bu, yüksek eşzamanlılık gerektiren ödeme veya tahsisat sistemleri kuran herkes için somut bir mimari dersi. İlginç hamle, şemayı kilit çekişmesinin etrafında şekillendirmektir: bağımsız kilitlenebilir nesne olarak kilitlenen bir sayaç yerine birim başına satırlar seçmek, kuyruk benzeri tahsisat için SKIP LOCKED kullanmak, birim başına satır yaklaşımını pratik tutmak için havuzu sınırlamak ve kilitlerin ödeme gibi insan ölçeğindeki beklemelere asla yayılmaması için transaction'ları kısa tutmak. Aynı kadar yararlı olan, belgelenmiş sınırlardır — tutarsız okumalar, adalet garantisinin olmaması, replication kısıtlamaları ve boş sonucun belirsizliği — ki bu kalıbı kopyalayan herhangi bir uygulama bunları açıkça tasarımına dahil etmek zorundadır.

  • #mysql
  • #shopify
  • #database-design
  • #concurrency
  • #e-commerce