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

> Parayı DB'nin garantisinde tutun: atomik koşullu `UPDATE ... WHERE balance >= 40` ya da `SELECT ... FOR UPDATE` kullanın, Redlock'u DB dışına bırakın.

- Soruldu: 2026-06-05
- Yanıtlandı: 2026-06-08
- Soran: Polat
- Etiketler: veritabani, queue, redis
- Kaynak: https://muhammetsafak.com/tr/sor-bakalim/bakiye-guncellemede-race-condition-pessimistic-lock-mu-redlock-mu/
- Dil: tr-TR
- Yazar: Muhammet Şafak

---
**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?


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.

## Kısa cevap

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. `FOR UPDATE` ile satır kilitlemeye geçtiğinde kilit sırasının tutarlı olması gerekir; deadlock'un nasıl doğduğunu ve nasıl önlendiğini [deadlock kaydında](/tr/sor-bakalim/veritabani-deadlock-tespiti-ve-onleme-kurallari/) anlatmıştım.

## Neden

1. **Invariant'ı uygulama değil veritabanı korumalı.** Okuma ve yazma tek ifadede birleştiğinde DB satır kilidini kendi yönetir; hem race'i çözer hem de `balance >= 40` gibi bir koşulla eksiye düşmeyi reddeder.
2. **Redlock, DB içi bir invariant için fazla kırılgan.** 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.
3. **Optimistic locking yoğun rekabette geri teper.** `version` kolonuna dayalı yaklaşım çakışma seyrekse ucuzdur, ama yoğun rekabette retry fırtınası yaratır — senin senaryonda aynı kullanıcı için art arda job geliyorsa bu risk gerçektir.

## Ne yapmalı

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. Etkilenen satır 0 ise işlem yetersiz bakiyeden başarısız demektir.
2. **Alternatif: `SELECT ... FOR UPDATE`.** Mantık 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'i değerlendir.** Satıra bir `version` kolonu ekle; güncellerken `WHERE version = ?` koy, eşleşmezse retry et.
4. **Redlock'u yalnızca DB dışı kaynak için kullan.** Korunması gereken şey bir DB satırı değilse — örneğin servisler arası bir kaynak — o zaman dağıtık kilit anlamlı olur.

**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

- [Laravel Queue ve Supervisor ile Asenkron İşlemler](/tr/blog/laravel-queue-ve-supervisor-ile-asenkron-islemler/) — Blog
- [Redis'te canlı leaderboard için neden Sorted Set kullanmalıyım?](https://muhammetsafak.com/tr/sor-bakalim/redis-veri-tipleri-leaderboard-icin-sorted-set/) — Sor Bakalım
- [Heap erişimini önlemek ve index-only scan almak için covering index'e (INCLUDE) ne zaman geçmeliyim?](https://muhammetsafak.com/tr/sor-bakalim/index-only-scan-covering-indexe-ne-zaman-gecmeliyim/) — Sor Bakalım
- [Correlation ID'yi HTTP isteğinden kuyruğa düşen job'lara kadar nasıl taşımalıyım?](https://muhammetsafak.com/tr/sor-bakalim/correlation-idyi-http-isteginden-kuyruga-dusen-joblara-kadar-nasil-tasimaliyim/) — Sor Bakalım
