Exponential Backoff + Jitter بالعربي: امنع هجوم الـ retries على سيرفرك
لو عندك 10,000 client متصلين بـ API، والسيرفر وقع ثانيتين، الـ clients كلهم هيحاولوا تاني في نفس اللحظة بالظبط لما يرجع. ده بيخلي اللي كان عطل بسيط يتحوّل لعطل طويل. الحل في 8 سطور كود، اسمه Exponential Backoff + Jitter، ومتبّن رسميًا من AWS و Google SRE.
المشكلة باختصار
الظاهرة دي اسمها Thundering Herd. السيرفر بيقع لثانيتين، كل الـ clients بتاخد خطأ، الـ retry logic عندهم بيحاول فورًا. لما السيرفر يقوم، بيستقبل 10,000 طلب في نفس الـ millisecond، فبيقع تاني. وهكذا لدورة لا تنتهي.
الحل الساذج إنك تستنى ثانية قبل كل retry. ده بيحل المشكلة جزئيًا، لكن الـ 10,000 client هيحاولوا كلهم بعد ثانية واحدة بالظبط — نفس التكدّس، بس مؤجل.
مثال بسيط: محل بعد انقطاع الكهرباء
تخيّل إن فيه محل بيخدم 500 عميل، وفجأة الكهرباء قطعت 5 دقائق. كل العملاء بيقفوا برّا المحل. لما الكهرباء ترجع، في 3 سيناريوهات:
- بدون أي تأخير: الـ 500 بيدخلوا مرة واحدة، الباب يتكسر، الموظف يفقد صوابه.
- تأخير ثابت (كله يستنى 30 ثانية): بعد 30 ثانية، الـ 500 بيدخلوا مرة واحدة برضه. المشكلة زي ما هي.
- تأخير متفاوت لكل عميل (jitter): كل عميل ياخد رقم عشوائي بين 0 و 60 ثانية. الطابور بيتوزّع تلقائيًا، والموظف بيخدم 8 عملاء في الدقيقة براحته.
ركز: السيناريو التالت هو اللي بينقذ الموقف. التوزيع العشوائي أهم من قيمة التأخير نفسها.
التعريف العلمي الدقيق
Exponential Backoff يعني إن وقت الانتظار بيتضاعف مع كل محاولة فاشلة. الصيغة الأساسية:
delay = base * (2 ^ attempt)يعني لو base = 100ms:
- المحاولة 1 بعد فشل: استنى 200ms
- المحاولة 2: استنى 400ms
- المحاولة 3: استنى 800ms
- المحاولة 6: استنى 6.4 ثانية
ده بيحل مشكلة تكرار الضرب السريع، لكنه لسه مش بيحل مشكلة التزامن. لأن كل الـ clients بتحسب نفس الـ delay بالظبط (200ms, 400ms, 800ms…)، فبيحاولوا كلهم في نفس اللحظات.
هنا بيدخل Jitter: عشوائية متعمّدة بتتضاف للـ delay علشان توزّعه. ورقة AWS الرسمية "Exponential Backoff and Jitter" بتوصي بصيغة Full Jitter: