تحديد المعدل (Rate Limiting) والتقييد (Throttling) في لغة C++: كيفية حماية واجهة برمجة التطبيقات (API) من الأحمال الزائدة

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

عندما تبدأ واجهة API الخاصة بك في الاختناق: مقدمة عن تحديد المعدل (Rate Limiting)



تخيل الموقف: لقد كتبت خادمًا مثاليًا بلغة C++. إنه سريع وفعال ويستخدم جميع نوى المعالج. تقوم بتشغيله في الإنتاج، وبعد خمس دقائق ينهار. ماذا حدث؟ اتضح أن بعض النصوص البرمجية المشاغبة قررت "اختبار" واجهة API الخاصة بك عن طريق إرسال آلاف الطلبات في الثانية.



هل هذا مألوف؟ إذا لم يكن كذلك - فأنت محظوظ. لكن عاجلاً أم آجلاً، يواجه كل مطور الحاجة إلى التحكم في الحمل. وهنا يأتي دور تحديد المعدل (Rate Limiting) و التقييد (Throttling) - آليتان قويتان تنقذان الخوادم من الأحمال الزائدة وتضمنان توزيعًا متساويًا للموارد.



في هذه المقالة، سنتعرف على كيفية تنفيذ هذه الآليات بلغة C++. لن تتعلم النظرية فحسب، بل ستحصل أيضًا على كود عملي يمكنك استخدامه فورًا في مشاريعك. هيا بنا!



تحديد المعدل (Rate Limiting) مقابل التقييد (Throttling): ما الفرق؟



قبل الغوص في الكود، دعنا نفصل بين هذين المفهومين بوضوح. كثير من الناس يخلطون بينهما، لكن الفرق موجود وهو جوهري.



تحديد المعدل (Rate Limiting)

هذا هو "الحاجز". أنت تقول: "في الثانية الواحدة - لا يزيد عن 10 طلبات. كل ما زاد عن ذلك - ممنوع (أو في قائمة الانتظار)". يحمي تحديد المعدل واجهة API الخاصة بك من الطلبات الانهيارية وهجمات DDoS والارتفاعات العشوائية في حركة المرور.



التقييد (Throttling)

هذا هو "منظم الصوت". أنت لا تمنع الطلبات تمامًا، بل تبطئ معالجتها. على سبيل المثال، إذا أرسل العميل 100 طلب في الثانية، فأنت تعالجها ولكن مع تأخير قدره 10 مللي ثانية بين كل طلب. التقييد هو طريقة أكثر "لباقة" لإدارة الحمل، فهو لا يتجاهل البيانات، بل يعمل فقط على تنعيم القمم.



في المشاريع الحقيقية، غالبًا ما يتم الجمع بين هاتين التقنيتين: أولاً التقييد للتنعيم، وعند تجاوز الحد الحرج - تحديد المعدل مع إرجاع خطأ 429 (Too Many Requests).



خوارزميات تحديد المعدل (Rate Limiting) في C++



هناك العديد من الخوارزميات الكلاسيكية. سنشرح اثنتين من الأكثر شيوعًا وفعالية: Token Bucket و Sliding Window. كلاهما سهل التنفيذ في C++ ويعطي نتائج ممتازة.



1. Token Bucket (دلو الرموز)

تخيل دلوًا، يتم فيه إسقاط N من الرموز كل ثانية. كل طلب يأخذ رمزًا واحدًا. إذا كان الدلو فارغًا - يتم رفض الطلب. بسيط وعبقري.



إليك التنفيذ بلغة C++ الحديثة باستخدام std::chrono:



#include <chrono>#include <mutex>#include <atomic>

class TokenBucket {public: TokenBucket(size_t max_tokens, double refill_rate) : max_tokens_(max_tokens) , refill_rate_(refill_rate) , current_tokens_(max_tokens) , last_refill_(std::chrono::steady_clock::now()) {}

bool try_consume() { std::lock_guard<std::mutex> lock(mutex_); // حساب عدد الرموز المتراكمة منذ المرة السابقة auto now = std::chrono::steady_clock::now(); auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - last_refill_); // إعادة ملء الدلو double tokens_to_add = elapsed.count() * refill_rate_ / 1000.0; current_tokens_ = std::min(max_tokens_, current_tokens_ + tokens_to_add); last_refill_ = now; // محاولة أخذ رمز if (current_tokens_ > 0) { --current_tokens_; return true; } return false; }

private: std::mutex mutex_; size_t max_tokens_; // السعة القصوى للدلو double refill_rate_; // الرموز في الثانية double current_tokens_; // العدد الحالي للرموز std::chrono::steady_clock::time_point last_refill_;};


الاستخدام:

TokenBucket limiter(10, 1.0); // 10 رموز، إعادة ملء 1 رمز/ثانية

// في معالج الطلب:if (limiter.tr

المدونات

توصيات الكتب