İçeriğe geç
Muhammet Şafak
en
Soran: Polat Cevaplandı:

Bakiye güncellemede race condition: Pessimistic Lock mı, Redlock mı?


Soru

Kullanıcı bakiyesinden para düşen bir kuyruk işimiz var. Kullanıcı hızlı arka arkaya iki işlem tetiklerse kuyrukta aynı kullanıcı için iki job oluşuyor; 10 paralel worker var. Worker 1 ve 2 aynı anda eski bakiyeyi okuyor (100 TL), ikisi de 40 düşüp 60 TL yazıyor (olması gereken 20 TL). Bu race condition'ı önlemek için Pessimistic Locking mi yoksa Redis dağıtık kilit (Redlock) mı kullanmalıyım?

Cevap

Kısa cevap: Yaşadığın şey klasik lost update (kayıp güncelleme) problemi. Para söz konusuysa invariant’ı DB’de tut; en temiz çözüm atomik koşullu bir UPDATE, ikinci tercih SELECT ... FOR UPDATE. Redlock’a koşma.

Senaryonun özü: oku-değiştir-yaz (read-modify-write) döngüsü paralel worker’lar arasında bölünüyor. İkisi de eski değeri okuyor, ikisi de üstüne yazıyor; biri kayboluyor. Çözüm bu döngüyü atomik kılmak.

  1. En iyisi: atomik koşullu UPDATE. UPDATE accounts SET balance = balance - 40 WHERE id = ? AND balance >= 40 yaz. Okuma ve yazma tek ifadede; uygulama tarafında kilit gerekmez. DB satır kilidini kendi yönetir, hem race’i çözer hem de balance >= 40 koşuluyla eksiye düşmeyi reddeder. Etkilenen satır 0 ise işlem yetersiz bakiyeden başarısız demektir.
  2. Alternatif: SELECT ... FOR UPDATE. Mantığın okuma ile yazma arasında karmaşıksa, transaction içinde bakiye satırını FOR UPDATE ile kilitle. İkinci worker o satıra geldiğinde birincinin commit’ini bekler; sıraya girerler, çakışma olmaz. Pessimistic locking budur.
  3. Düşük çakışmada optimistic locking de iş görür. Satıra bir version kolonu ekle; güncellerken WHERE version = ? koy, eşleşmezse retry et. Çakışma seyrekse ucuzdur, ama yoğun rekabette retry fırtınası yaratır.
  4. Redlock’u yalnızca DB dışı kaynak için kullan. Redis dağıtık kilidi (Redlock), korunan şey tek bir DB satırı olmadığında (servisler/kaynaklar arası koordinasyon) anlamlıdır — ve clock kayması/timeout gibi köşe durumları vardır. Bir bakiye DB’nin transaction’ıyla zaten korunabiliyorken onu dağıtık bir kilide emanet etme.

Sonuç: Atomik koşullu UPDATE (ya da SELECT FOR UPDATE) kullan; Redlock’u sadece DB dışı kaynaklar için sakla. Para için kuralı transaction’ın garanti ettiği yerde — DB’de — tut; dağıtık kilit, veritabanının kendisinin zaten zorlayabileceği bir invariant’ı korumak için fazla kırılgan bir araçtır.

İlgili Yazılar

Etiketler: #veritabanı#kuyruk#redis
Paylaş:

Yorumlar

Yorum yapmak için GitHub hesabınızla giriş yapmanız yeterli. Yorumlar GitHub Discussions üzerinde saklanır.

Diğer Sorular

Tüm sorular

Sitede Ara

Yazı, proje ve sayfalarda arama yapmak için yazmaya başlayın.

Esc ile kapat Pagefind ile güçlendirildi