Redis میں سلائیڈنگ ونڈو ریٹ لمٹر (Rate Limiter) بنانا

گزشتہ سہ ماہی میں دو بار صبح 9:00 بجے سے پہلے ہمارا YouTube API کوٹہ ختم ہو گیا۔ اس کی وجہ سے ہمارے آدھے علاقوں کے ٹرینڈنگ فیڈز پرانے (stale) ہو گئے۔

مسئلہ ٹریفک میں اضافہ نہیں تھا۔ بلکہ مسئلہ ہمارا ریٹ لمٹر (rate limiter) تھا۔

ہم ایک فکسڈ ونڈو کاؤنٹر (fixed-window counter) استعمال کر رہے تھے۔ اس کی وجہ سے اگر API کالز ونڈو کی حد (boundary) کے بالکل قریب پہنچتی تھیں، تو دو بڑے جھٹکے (bursts) آسانی سے گزر جاتے۔ 8 علاقوں پر مشتمل ایک عالمی پائپ لائن کے لیے، یہ باؤنڈری اوورلیپ اکثر ہوتا تھا۔ اس نے ہمارے روزانہ کے مقررہ کوٹہ کو بجٹ کے ضیاع میں بدل دیا۔

میں نے فکسڈ ونڈو کو Redis sorted sets کا استعمال کرتے ہوئے سلائیڈنگ ونڈو لاگ (sliding window log) سے بدل دیا۔

یہ اس طرح کام کرتا ہے:

  • ٹائم اسٹیمپ کے ساتھ درخواست ریکارڈ کرنے کے لیے ZADD کا استعمال کریں۔
  • ونڈو سے باہر کی پرانی انٹریز کو ہٹانے کے لیے ZREMRANGEBYSCORE کا استعمال کریں۔
  • یہ گننے کے لیے کہ ونڈو میں کتنی درخواستیں باقی ہیں، ZCARD کا استعمال کریں۔
  • غیر فعال (idle) کیز کو خودکار طریقے سے صاف کرنے کے لیے PEXPIRE کا استعمال کریں۔

یہ طریقہ بالکل درست ہے۔ اس میں کسی حد (boundary) کے درمیان پھنسنے کا خطرہ نہیں ہے۔

میں نے اسے Redis میں ایک Lua اسکرپٹ کے ذریعے نافذ کیا۔ اس سے یہ یقینی بنتا ہے کہ چیک کرنے اور ریکارڈ کرنے کا پورا عمل ایٹامک (atomic) ہو۔ اگر آپ یہ اقدامات ایپلی کیشن کوڈ میں چلائیں گے، تو ریس کنڈیشنز (race conditions) کی وجہ سے اضافی درخواستیں گزر سکتی ہیں۔

پروڈکشن کے لیے اہم تکنیکی فیصلے:

  • Redis TIME کا استعمال کریں: اپنے ایپلی کیشن سرورز کے ٹائم اسٹیمپ استعمال نہ کریں۔ سرورز کے درمیان کلاک سکو (clock skew) ونڈو کی درستگی کو خراب کر دیتا ہے۔
  • ویٹڈ کاسٹ (Weighted costs): تمام API کالز برابر نہیں ہوتیں۔ ایک سرچ کال کی قیمت 100 یونٹ ہو سکتی ہے جبکہ ویڈیو لسٹ کی قیمت 1 ہو سکتی ہے۔ میرا اسکرپٹ ہر کال کے لیے متعدد ممبرز شامل کر کے اسے سنبھالتا ہے۔
  • درست Retry-After: sorted set میں سب سے پرانی انٹری کو دیکھ کر، سسٹم بالکل درست حساب لگاتا ہے کہ صلاحیت (capacity) کب دستیاب ہوگی۔
  • فیل سیف لاجک (Fail-safe logic): میں EVALSHA کے ساتھ EVAL فال بیک استعمال کرتا ہوں۔ اگر ری اسٹارٹ کے دوران Redis اسکرپٹ کیش صاف ہو جائے، تو ایپلی کیشن اسے بہتر طریقے سے سنبھال لیتی ہے۔

اس کا نقصان میموری کی صورت میں ہے۔ ہر درخواست تقریباً 100 بائٹس لیتی ہے۔ 10,000 یونٹ کے روزانہ کوٹہ کے لیے، یہ صرف تقریباً 1 MB میموری ہے۔ زیادہ تر استعمال کے کیسز کے لیے، یہ درستگی اس قیمت کے قابل ہے۔

اس تبدیلی کے بعد سے، ہمارا کوٹہ ایک بار بھی ختم نہیں ہوا۔ ہمارے کام 403 ایررز آنے کے بجائے باوقار طریقے سے رک جاتے ہیں۔

اگر آپ کا ریٹ لمٹر گھڑی کے کسی گول نمبر (round number) پر ری سیٹ ہوتا ہے، تو آپ کے پاس کوئی حد نہیں ہے۔ بلکہ آپ کے پاس ایک لup ہول (loophole) ہے۔

ماخذ: https://dev.to/ahmet_gedik778845/building-a-sliding-window-rate-limiter-in-redis-for-a-multi-region-video-api-50ni