Son ürünü iki kişinin aynı anda satın alması nasıl engellenir?

Bir e-ticaret sitesi geliştirdiğinizi düşünelim, hangi dilde olduğu fark etmez, güncel teknolojiler kullandığınızı varsayalım.

Trafik artmaya başladı ve ürün satışları da doğal olarak artıyor, ve zaman zaman özellikle düşük stoklu ürünlerde olmayan stokların satışını fark ettiniz.

Stok’da son ürün kaldığında birden fazla kişinin bu ürünü satın aldığını fark ettiniz.

Bunun literatürdeki adı race condition ve overselling şeklinde.

Bu yazıda bu tarz bir durumda neler yapılabilir bundan bahsedeceğim, özellikle veritabanı seviyesine odaklanacağız. Bu operasyonları güvenli şekilde gerçekleştirmemiz için aşağıdaki veritabanlarından birini kullandığınızı varsayıyorum.

Önerilen veritabanları

  • MSSQL
  • MYSQL
  • POSTGRESQL

Bu veritabanlarının hepsi bu yazıda işleyeceğimiz özellikleri destekleyen SQL veritabanı yazılımlarıdır.

Tüm yöntemlerde transaction açmanız ve başarılı olursa commit etmeniz gerektiğini hatırlatmak isterim, her maddede bunu tekrar etmemek için baştan söylüyorum.

Hemen yöntemlere geçelim.

Database Transaction + Lock

Bu yöntem, çözümlerimiz arasında en çok kullanılan ve klasik bir yöntem diyebiliriz.

Bu yöntemin temel mantığı veritabanında işlem yapmadan önce bu işlemi yaptığımız satırlarda başkası işlem yapmasın demek oluyor.

Örnek SQL

SQL
SELECT * FROM products WHERE id = 1 FOR UPDATE;

İşlemin başında satır kilitlenir.

Diğer kullanıcılar işlemin bitmesini beklerler.

İlk işlem bitince sıradaki işlem ile devam edilir.

Yoğun trafikte yavaşlatır.

Deadlock riski yaratır.

Kullanım örneği ( Temsili kod SQL)

SQL
BEGIN TRANSACTION

SELECT stock FROM products WHERE id=1 FOR UPDATE

IF stock > 0:
    UPDATE products SET stock = stock - 1
    COMMIT
ELSE:
    ROLLBACK

Optimistic Lock

Bu yöntem benim de en sevdiğim ve bir çok noktada bolca kullandığım bir yöntem, Optimistic Lock yöntemi yani versiyon sütunu eklemek.

Ben sadece stok değil şifre değiştirme gibi durumlarda da bu sistemi kullanıyorum, veri tutarlılığını özellikle JWT üzerinden kontrol etmek için en garanti yöntem ama tabi bu yazının konusu JWT değil.

Burada kullanacağımız mantık çok basit, bir version ve updated_at sütunu ile verinin sorguladığımız andaki ve güncellediğimiz andaki tutarlılığını kontrol ediyoruz.

SQL
UPDATE products
SET stock = stock - 1, version = version + 1
WHERE id = 1 AND version = 5;

Dediğim gibi bir çok noktada kullanılabilecek bir yöntem. Farklı senaryolarda da ilaç gibi geliyor.

Tek sıkıntısı çakışma durumunda işlemi iptal etmekden başka çaremiz yok.

Atomic Update

SQL
UPDATE products
SET stock = stock - 1
WHERE id = 1 AND stock > 0;

Burada da aslında benzer bir mantık, stok sıfır olmadığı sürece bir azaltmasını rica ediyoruz veritabanından. Bu çok da basit bir yöntem ben çok tercih etmiyorum ama tabi siz bilirsiniz.

Yazımızın genelinden de anlayabileceğiniz gibi amacımız veritabanımızın sağladığı özelliklere öncelik vermek.

Şimdi sırada ise farklı bir yöntem var, ek bir yazılımdan destek alacağız.

Queue / Message Queue (RabbitMQ vb.)

Bankacılık uygulamalarına kadar yüksek trafikli tüm işlemlerde bu yöntem kullanılır, Siparişler sıraya alınır ve arkaplanda kullanıcıyı da bekletmeden işlenir. Sonrasında kullanıcıya gerekli bildirimler yapılır.

  • Sipariş bekleme listesine alınır
  • Kulalnıcıya siparişinin onay beklediği ekran gösterilir
  • Arkaplanda sipariş işlenir (QUEUE)
  • Kullanici tarayici veya mail yoluyla bilgilendirilir/yönlendirilir

Rezervasyon Sistemi

Bir başka yöntem de kullanıcılar için sepete eklendiğinde rezerve stoklar atamaktır, bunun örneği bu yazımız için çok uzun olacak o yüzden çok ayrıntıya girmiyorum.

  • Kullanıcı sepete ekler
  • Sepete ekleme ile birlikte bir stok tutucu oluşturulur ve ürün bu kullancıya rezerve edilir bir süreliğine.
  • kullanıcı satın alma sırasında yine stok kontrolü ile birlikte satın alır
  • kullanıcı belli bir süre satın almazsa stok serbest bırakılır.

Sonuç

Benim önerim kesinlikle QUEUE sistemleri de içinde barındıran hibrit bir sistem.

Örneğin Rabbit MQ + Database Transaction + Lock

  • Önce sipariş queue ye atılır.
  • Kullanıcı bekleme ekranına gönderilir.
  • Optimistik Lock + Database Transaction Lock ile birlikte sipariş işlenir.
  • Kullanıcı bilgilendirir.

Yorumlar

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir