Distributed Lock بـ Redis Redlock — الدليل التنفيذي للمحترف
مستوى المقال: محترف — هذا المقال بيفترض إنك فاهم Redis basics و SET NX و event loop و async/await في Node.js، وعندك تجربة سابقة مع microservices أو background workers.
لو فريقك بيشغّل scheduled job كل صباح يبعت إيميل للعملاء، وفجأة لقيت 5 آلاف عميل استلموا الإيميل أربع مرات في يوم واحد، المشكلة مش في كود الإيميل. المشكلة إن عندك 5 workers في الإنتاج، وكلهم اشتغلوا في نفس الثانية. Distributed Lock هو الحل، لكن استخدامه بشكل غلط بيدّيك إحساس زائف بالأمان وبيتسبّب في bugs أسوأ. هنا تحت، Redlock شغّال في 90 سطر Node.js، مع شرح ليه الـ SETNX لوحده مش كافي في cluster، وحالات حقيقية Redlock فيها unsafe.
المشكلة باختصار
لمّا يكون عندك أكتر من instance من نفس الخدمة، أي عملية المفروض تتنفّذ مرة واحدة فقط بتبقى في خطر. أمثلة من الإنتاج: إرسال الفواتير الشهرية، تجديد اشتراكات Stripe، إعادة فهرسة Elasticsearch، ضغط ملفات S3 يوميًا، تنظيف الـ cache. الحلول الساذجة (Cron على instance واحد، أو DB row lock) بتفشل عند failover أو بتقفل DB connection لدقايق طويلة.
مثال للمبتدئ: مفتاح الحمام في المكتب
تخيّل مكتب فيه حمّام واحد و 5 موظفين. لو مفيش تنسيق، ممكن اتنين يدخلوا في نفس الوقت. الحل البسيط إن في مفتاح واحد بس. اللي ياخده يدخل، يرجّعه يطلع. كده اتنين عمري ما يقدروا يدخلوا في نفس اللحظة. لكن في مشكلة: لو الموظف اللي معاه المفتاح غاب 4 ساعات، الباقي هيستنوا للأبد. علشان كده بنحط timeout على المفتاح: لو معدّاش 10 دقايق، ينفك تلقائيًا.
ده بالظبط اللي بيعمله الـ Distributed Lock: مفتاح موحّد بين كل الـ workers، مع timeout (TTL) لحماية النظام لو الـ worker اللي ماسك القفل وقع.
التعريف العلمي الدقيق
Distributed Lock هو primitive بيوفّر mutual exclusion عبر processes موزعة على شبكة. حسب تعريف Lamport في ورقة "Time, Clocks, and the Ordering of Events in a Distributed System" (1978)، أي قفل موزع لازم يحقق ثلاث خصائص:
- Safety: في أي لحظة، client واحد فقط بيمسك القفل.
- Liveness A: لازم القفل ينفكّ في النهاية حتى لو الـ client اللي ماسكه وقع (Deadlock-free).
- Liveness B: لازم clients تقدر تاخد القفل لما يبقى متاح (Fault Tolerance).
المرجع: Lamport, Communications of the ACM, 1978.
ليه SET NX EX لوحده مش كفاية في الإنتاج
أبسط implementation هو السطر ده على Redis واحد: