تحديد معدل الطلبات في Rust: إدارة فعالة للحمل
\n\nتحديد معدل الطلبات (Rate limiting) هو آلية أساسية لحماية وتحسين خدمات الويب وواجهات برمجة التطبيقات (API) وتطبيقات الشبكات. في نظام Rust البيئي، توجد عدة مكتبات ناضجة تنفذ خوارزميات مختلفة: من خوارزمية token-bucket الكلاسيكية إلى الأساليب التكيفية الحديثة. في هذه المقالة، سنستعرض ثلاث مكتبات رئيسية: governor و leaky-bucket و ratelimit، مع أمثلة على الكود وتوصيات للاختيار.
1. مكتبة governor — المعيار الذهبي
\n\ngovernor هي المكتبة الأكثر شيوعًا ومرونة لتحديد معدل الطلبات. تنفذ خوارزمية Generic Cell Rate Algorithm (GCRA)، والتي تضمن الالتزام الدقيق بالحدود بأقل تأخير. تدعم الأوضاع المتزامنة وغير المتزامنة، و middleware لإطارات Actix-web و Axum و Rocket.
\n\nمثال أساسي مع governor
\nuse governor::{DefaultKeyedRateLimiter, Quota, RateLimiter};\nuse std::num::NonZeroU32;\nuse std::time::Duration;\n\nfn main() {\n // السماح بـ 5 طلبات في الثانية\n let quota = Quota::per_second(NonZeroU32::new(5).unwrap());\n let limiter = RateLimiter::direct(quota);\n\n for i in 0..10 {\n match limiter.check() {\n Ok(_) => println!("الطلب {} مسموح به", i),\n Err(_) => println!("الطلب {} مرفوض (تجاوز الحد)", i),\n }\n std::thread::sleep(Duration::from_millis(100));\n }\n}\n\nالنسخة غير المتزامنة مع الانتظار
\nuse governor::{Quota, RateLimiter};\nuse std::num::NonZeroU32;\nuse tokio::time::{sleep, Duration};\n\n#[tokio::main]\nasync fn main() {\n let limiter = RateLimiter::direct(Quota::per_second(\n NonZeroU32::new(2).unwrap(),\n ));\n\n for i in 0..5 {\n limiter.until_ready().await;\n println!("تمت معالجة الطلب {}", i);\n sleep(Duration::from_millis(300)).await;\n }\n}\n\nالإمكانيات الرئيسية لـ governor:
\n- \n
- دعم الحدود المفتاحية (لكل عنوان IP، لكل مستخدم) عبر
KeyedRateLimiter\n - التكامل مع
towermiddleware لخوادم HTTP \n - استراتيجيات قابلة للتخصيص: الانتظار، الرفض، التباطؤ التكيفي \n
- استهلاك ضئيل للذاكرة (عداد ذري واحد لكل محدد) \n
2. مكتبة leaky-bucket — البساطة والموثوقية
\n\nleaky-bucket تنفذ خوارزمية "الدلو المتسرب" الكلاسيكية. وهي مثالية لتنعيم الأحمال الذروة، عندما تحتاج لضمان تدفق متساوٍ للطلبات. المكتبة خفيفة الوزن ولا تتطلب تبعيات خارجية.
\n\nمثال مع leaky-bucket
\nuse leaky_bucket::RateLimiter;\nuse std::time::Duration;\n\n#[tokio::main]\nasync fn main() {\n let limiter = RateLimiter::builder()\n .initial(10) // المخزون الأولي من الرموز\n .interval(Duration::from_secs(1)) // فترة إعادة التعبئة\n .refill(5) // عدد الرموز المضافة خلال الفترة\n .max(20) // الحد الأقصى لعدد الرموز\n .build();\n\n for i in 0..15 {\n limiter.acquire_one().await;\n println!("تم تنفيذ الطلب {}", i);\n }\n}\n\nمميزات leaky-bucket:
\n- \n
- دعم واجهات برمجة التطبيقات غير المتزامنة والحاجزة \n
- إمكانية ضبط وضع "الانفجار" (الارتفاعات المؤقتة) \n
- تحرير تلقائي للرموز عند الخمول \n
3. مكتبة ratelimit — نهج بسيط
\n\nratelimit هي أبسط مكتبة، تنفذ نافذة منزلقة بفواصل زمنية ثابتة. مناسبة للسيناريوهات البسيطة التي لا تتطلب دقة عالية.
\n\nمثال مع ratelimit
\nuse ratelimit::Ratelimiter;\nuse std::time::Duration;\n\nfn main() {\n let mut limiter = Ratelimiter::builder(10, Duration::from_secs(1))\n .