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 redis2import time3import uuid45class DistributedLock:6def __init__(self, redis_client, key, timeout=10):7self.redis = redis_client8self.key = key9self.timeout = timeout10self.token = str(uuid.uuid4())1112def acquire(self):13while True:14result = self.redis.set(self.key, self.token, nx=True, ex=self.timeout)15if result:16return True17time.sleep(0.1)1819def release(self):20lua_script = """21if redis.call("get", KEYS[1]) == ARGV[1] then22return redis.call("del", KEYS[1])23else24return 025end26"""27self.redis.eval(lua_script, 1, self.key, self.token)2829# Kullanım30redis_client = redis.Redis(host='localhost', port=6379, decode_responses=True)3132lock = DistributedLock(redis_client, 'account_123_lock', timeout=5)33lock.acquire()34print("Lock alındı")3536# Kritik bölüm: hesaptan para çekme37balance = redis_client.get('account_123_balance')38print(f"Bakiye: {balance}")3940lock.release()41print("Lock serbest bırakıldı")Beklenen çıktı:
1Lock alındı2Bakiye: 10003Lock 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# İşlem4finally: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.
1 yorum
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