NGINX rate limiting: احمِ /login قبل ما يوقع التطبيق
هتطلع من المقال بإعداد NGINX عملي يقلل ضغط bursts على التطبيق، ويرجع 429 بوضوح بدل ما يتحول الضغط إلى 5xx وبطء عام.
مستوى القارئ: متوسط
المشكلة باختصار
لو عندك صفحة login أو endpoint دفع أو API بحث، أكبر خطر مش دايمًا متوسط الترافيك. الخطر هو burst صغير لكنه مركز. مثال واقعي: موقع SaaS يستقبل 40 طلب/ثانية عادي، لكن bot واحد يضرب /login بـ 120 طلب/ثانية لمدة دقيقة. اللي بيحصل فعلاً إن app instances تستهلك CPU في hashing أو DB checks، وبعدها المستخدم الطبيعي يشوف latency عالي.
الطريقة الشائعة الغلط إنك تزود replicas فورًا. ده يحل جزء من السعة، لكنه لا يمنع نفس العميل من استهلاك موارد أكثر. أفضل طريقة هنا إنك تعمل بوابة خفيفة قبل التطبيق: NGINX يمرر المعدل المقبول، يؤخر أو يرفض الزيادة، ويخلي التطبيق يشوف traffic ثابت.
الفكرة بمثال بسيط
ركز في المثال ده: عندك باب مكتب يسمح بدخول 10 أشخاص كل ثانية. لو وصل 30 شخص مرة واحدة، الباب ممكن يسمح لـ 10، ويخلّي 20 في طابور صغير، أو يرفض جزء منهم لو الطابور امتلأ. ده بالظبط منطق limit_req. NGINX يستخدم leaky bucket: معدل ثابت، وburst مساحة مؤقتة للطلبات الزائدة.
التعريف الأدق: limit_req_zone ينشئ shared memory zone لحفظ حالة كل key، وغالبًا يكون key هو IP العميل عبر $binary_remote_addr. بعد ذلك limit_req يطبق الحد داخل location معين. لو الطلبات زادت عن المعدل، NGINX يؤخرها أو يرفضها حسب إعداد burst وnodelay.
إعداد NGINX جاهز
الافتراض إن عندك NGINX أمام تطبيق Node.js أو Python، ونقطة /login مكلفة لأنها تعمل password hashing أو DB lookup. هنبدأ بحد محافظ: 10 طلبات/ثانية لكل IP، مع burst يساوي 20. هذا مناسب كبداية لتطبيق متوسط، وليس قاعدة ثابتة لكل الأنظمة.
http {
limit_req_zone $binary_remote_addr zone=login_per_ip:10m rate=10r/s;
server {
listen 80;
server_name example.com;
limit_req_status 429;
limit_req_log_level notice;
location /login {
limit_req zone=login_per_ip burst=20 nodelay;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://app_backend;
}
location / {
proxy_pass http://app_backend;
}
}
}
الـ trade-off هنا واضح. nodelay يخلي أول burst يعدي بسرعة بدل الانتظار، وده يحافظ على تجربة المستخدم الحقيقي لو ضغط مرتين أو الشبكة أعادت الطلب. في المقابل، لو bot ذكي يرسل bursts قصيرة، جزء منها هيوصل للتطبيق. لو هدفك حماية endpoint مكلف جدًا، جرّب حذف أو تقليل .