المستوى المطلوب: محترف (Senior Backend Engineer / DevOps)
لو الـ API بتاعك بيوصله 50 ألف طلب في الثانية ومحتاج تمنع زبون واحد ياخد كل الموارد، الحل المعتاد هو Redis مع SETEX أو INCR + TTL. الحل ده بيكلّفك round-trip شبكة كل طلب، يعني 1.2 مللي ثانية فوق كل request حتى لو الـ Redis في نفس الـ data center. Token Bucket في الذاكرة بينزّل الرقم ده لـ 78 ميكروثانية، ويخدم نفس الحمل من غير ما يلمس الشبكة. المقال ده يشرح ليه، إمتى يصلح، وإمتى Redis لسه أذكى.
Token Bucket: الـ Rate Limiter اللي بيشتغل من جوّا الـ process
المشكلة باختصار
أي API عام بيستقبل 100% من الـ traffic من العالم الخارجي. زبون واحد عنده bug في الـ retry logic ممكن يبعتلك 12 ألف طلب في الثانية ويوقّع باقي العملاء. الحل المنطقي: حد أقصى لكل API key. التطبيق الشائع: Redis. لكن Redis كحل rate limiting بيدفعك ضريبة latency في كل طلب صحيح، مش بس الطلبات اللي بترفض. على workload فيه 99% من الطلبات بتمر، بتدفع 1.2 مللي ثانية ضائعة على 99% من الـ traffic علشان تحمي نفسك من 1%.
المثال البسيط: ماكينة الكافيه
تخيّل ماكينة كافيه عند مدخل بنك. الماكينة فيها 100 كوب جاهز كل لحظة (ده الـ capacity). كل ثانية، الموظف بيحط فيها كوب جديد (ده الـ refill rate). لو جالك 100 عميل دفعة واحدة، تخدمهم كلهم في الحال — لأن الكوبايات موجودة. لو جا العميل رقم 101، يستنى ثانية واحدة لما الكوب التالي ينزل. لو الماكينة فاضية وجا عميل، إما يستنى أو ينصرف.
الفكرة دي بالظبط هي Token Bucket. كل توكن في الـ bucket = إذن لطلب واحد. الـ bucket بيتلي تلقائيًا بمعدل ثابت، بس مش ممكن يفيض. لما يفيض، التوكنز الزيادة بترمى. ده اللي بيخلّيه يدعم burst محدودة (لما الـ bucket مليان) ويفرض sustained rate في نفس الوقت.
التعريف العلمي الدقيق
Token Bucket Algorithm، اتعرّف رسميًا في RFC 2697 (A Single Rate Three Color Marker, 1999)، فيه ثلاث متغيّرات:
- B (Burst Size): أقصى عدد توكنز ممكن الـ bucket يحتفظ بيه. ده بيحدد قد إيه ممكن تتحمّل spike مفاجئ.
- R (Refill Rate): عدد التوكنز اللي بتضاف لكل ثانية. ده الحد المستدام (sustained rate).
- tokens: العدّاد الحالي. لما يقل عن 1، الطلب يترفض أو يتأجل.
الفرق بينه وبين Leaky Bucket: الـ Leaky Bucket بيفرض معدّل خروج ثابت دايمًا (queue + drain rate)، بس مش بيدعم bursts. Token Bucket بيدعم bursts لحد B ثم يحدّ بـ R. الفرق بينه وبين Sliding Window Counter: الـ Sliding Window أدق في الحدود الزمنية، بس بياكل ذاكرة O(N) ووقت O(log N) لكل طلب. Token Bucket بياكل O(1) في الاتنين.