Redis'te Distributed Lock: Race Condition'dan Kurtulma

Birden çok sunucu ya da worker aynı kaynağa aynı anda erişmeye çalışırsa veri bozulması yaşarsın. Redis'te distributed lock kullanarak bu sorunu çözebilirsin.

Sorun şu: Ödeme işlemi yapan bir fonksiyon var. İki worker aynı anda çalışıyor ve ikisi de aynı hesaptan para çekmeye başlıyor. Kilitsiz çalışırsa, bakiye iki kez çekilebilir. Distributed lock bu durumu engeller.

Redis'te lock uygulamanın en basit yolu SET NX (Not eXists) komutudur. Anahtar varsa yazma, yoksa yaz. Böylece ilk worker lock alır, diğerleri bekler.

1import redis
2import time
3import uuid
4
5class DistributedLock:
6def __init__(self, redis_client, key, timeout=10):
7self.redis = redis_client
8self.key = key
9self.timeout = timeout
10self.token = str(uuid.uuid4())
11
12def acquire(self):
13while True:
14result = self.redis.set(self.key, self.token, nx=True, ex=self.timeout)
15if result:
16return True
17time.sleep(0.1)
18
19def release(self):
20lua_script = """
21if redis.call("get", KEYS[1]) == ARGV[1] then
22return redis.call("del", KEYS[1])
23else
24return 0
25end
26"""
27self.redis.eval(lua_script, 1, self.key, self.token)
28
29# Kullanım
30redis_client = redis.Redis(host='localhost', port=6379, decode_responses=True)
31
32lock = DistributedLock(redis_client, 'account_123_lock', timeout=5)
33lock.acquire()
34print("Lock alındı")
35
36# Kritik bölüm: hesaptan para çekme
37balance = redis_client.get('account_123_balance')
38print(f"Bakiye: {balance}")
39
40lock.release()
41print("Lock serbest bırakıldı")

Beklenen çıktı:

Reklam · TEST
AdSense Test ReklamıYazı arası (gönderi içi) · Yazı arası
1Lock alındı
2Bakiye: 1000
3Lock serbest bırakıldı

Kod açıklaması: Uuid ile benzersiz bir token oluşturuyoruz. SET NX komutu lock'u yaratırken, Lua script ile sadece kendi token'ı olan worker silebiliyor. Bu, yanlışlıkla başka bir worker'ın lock'unu silmesini engeller.

Timeout (ex=5) çok önemli. Worker crash'lerse, lock sonsuza kadar kalır ve sistem kilitlenir. 5 saniye sonra otomatik silinir.

Sık yapılan hata: Lock release etmeden exception fırlatırsan, lock kalıyor. Try-finally kullan.

1try:
2lock.acquire()
3# İşlem
4finally:
5lock.release()

Redis cluster'da çalışırken, bknz: Serverless vs Konteyner: Hangi İş Yükü Nereye Gider, ek olarak, Redlock algoritması daha güvenli bir seçenektir. Ama basit durumlar için SET NX yeterli.

Reklam · TEST
AdSense Test ReklamıGönderi altı · Görüntülü
konu hakkında tepkinizi verebilirsiniz
  • neyseartik

    rediste bu şekilde çözmek güvenli değil aslında lock expire olmaz ya da process ölürse kilit kalır başka worker da sonsuz bekler set nxe expiry ve uuid lazım yoksa üretim ortamında sorun olur