لو عندك API بيخدم 10 آلاف مستخدم، وواحد بس بيبعت 500 طلب في الثانية، ممكن ياكل الـ CPU ويوقّف الباقي. Token Bucket بيحدّد الشخص ده في سطر واحد من غير ما يظلم اللي بيستخدم API بشكل طبيعي وعايز يبعت 20 طلب في ثانية واحدة كـ burst.
Token Bucket: خوارزمية الـ Rate Limiting اللي Stripe وCloudflare وAWS شغالين بيها
المشكلة باختصار
أي API مفتوح على الإنترنت لازم يحط حد لعدد الطلبات لكل مستخدم. من غير الحد ده، سكربت واحد غلط أو مهاجم ممكن يستهلك كل الموارد ويوقّف الخدمة عن الباقي. الطريقة الساذجة هي "ممنوع أكتر من 100 طلب في الدقيقة"، لكنها بتفشل مع الاستخدام الحقيقي لأن المستخدمين بيبعتوا طلبات في bursts، مش بالتساوي.
تخيّل معايا تانك مياه عليه حنفية
عندك تانك مياه صغير، سعته 10 لتر بالظبط. فوقه حنفية بتنقّط مياه بمعدل ثابت: 1 لتر كل ثانية. لما عايز تشرب، لازم تاخد كوباية (لتر) من التانك. لو التانك فاضي، لازم تستنى الحنفية تنقّط لتر جديد.
الحلو في التانك إنه بيتخزّن فيه مياه. يعني لو قعدت ساعة من غير ما تشرب، هيبقى مليان (10 لتر)، وتقدر تشرب 10 كوبايات وراء بعض كـ burst. لكن متوسط الاستهلاك على المدى الطويل لازم يظل 1 لتر في الثانية، لأن ده معدل الحنفية.
الـ Token Bucket هو نفس التانك بالظبط:
- التانك = الـ bucket (ذاكرة صغيرة بتعدّ الـ tokens المتاحة).
- سعة التانك =
capacity(أقصى burst مسموح). - معدل الحنفية =
refill_rate(المتوسط المسموح على المدى الطويل). - الكوباية = الطلب (request) اللي بياخد token واحد أو أكتر.
كل طلب بييجي: لو في token ناقص منه وخد وعدّي. لو مفيش، ارفضه بـ 429 Too Many Requests. بسيطة.
التعريف العلمي الدقيق
Token Bucket خوارزمية مُعرَّفة رسميًا في سياق traffic shaping على الشبكات (موثّقة في Wikipedia وIntro to Computer Networks من جامعة Loyola). الخوارزمية عندها أربع متغيرات:
capacity(C): أقصى عدد tokens ممكن التانك يحمله.refill_rate(r): عدد الـ tokens اللي بتتضاف في الثانية.tokens: العدد الحالي من الـ tokens (≤ C).last_refill_time: آخر لحظة حسبنا فيها عدد الـ tokens الجديدة.
لما يجي طلب في لحظة t:
- نحسب الـ tokens الجديدة:
new_tokens = (t - last_refill_time) × r - نحدّث:
tokens = min(C, tokens + new_tokens) - نحدّث:
last_refill_time = t - لو
tokens ≥ 1: انقص واحد واسمح بالطلب. - غير كده: ارفض الطلب.
الفرضية اللي بيشتغل عليها المقال ده: عندك API واحد أو cluster يتم فيه تنسيق الـ state عبر Redis، وعدد الطلبات في حدود ≤ 50K طلب/ثانية. فوق كده محتاج حلول distributed أعقد.