آرش قصد دارد یک وبسرویس خفن پیادهسازی کند، اما او میداند که از همان ابتدای کار، تعداد درخواستهای کاربران به endpoint هایی که بار پردازشی بالایی دارند بسیار زیاد خواهد بود. بنابراین او تصمیم گرفته که از rate limiter استفاده کند. از آنجایی که او نمیداند این rate limiter را چگونه پیادهسازی کند، از شما خواسته تا آن را برایش پیادهسازی کنید.
جزئیات پروژه
پروژهی اولیه را از این لینک دانلود کنید. ساختار فایلهای پروژه بهصورت زیر است:
rate-limit
├── db
│ └── connection.go
├── handlers
│ └── root.go
├── limiters
│ ├── by_app_key.go
│ └── by_ip.go
├── test
│ └── ratelimit_sample_test.go
├── go.mod
├── go.sum
└── main.go
%align_right_start%
وابستگی time/rate
در پروژه تعریف شده و برای پیادهسازی rate limiter باید از آن استفاده کنید.
%align_end%
پایگاه داده
در این پروژه از پایگاه دادهی PostgreSQL استفاده شده است. برنامه شامل جدولی با نام app_keys
است که شامل دو ستون id
از نوع BIGSERIAL
و key
از نوع VARCHAR(255)
است.
در پکیج db
تابعی با نام GetConnection
تعریف شده که باید از آن برای دریافت کانکشن دیتابیس استفاده کنید. میتوانید اطلاعات اتصال به دیتابیس را در این فایل تغییر دهید.
روتها
تنها یک روت با آدرس /
در برنامه تعریف شده است که میتوان rate limiter های مختلف را روی handler آن اعمال کرد.
تابع ByIp
این تابع بهترتیب شامل سه پارامتر زیر است:
next
از نوعhttp.Handler
: همان handler اصلی روت است.refillRate
از نوعrate.Limit
: میزان افزایش تعداد درخواستهای مجاز کاربر در هر ثانیه (برای مثال اگر مقدار آن برابر با ۳ باشد، در هر ثانیه، ۳ واحد به تعداد درخواستهای مجاز کاربر اضافه میشود، به شرطی که تعداد درخواستهای مجاز فعلیاش کوچکتر ازtokenBucketSize
باشد.)tokenBucketSize
از نوعint
: سقف تعداد درخواستهای پیاپی کاربر
این تابع را طوری پیادهسازی کنید که درخواستها را براساس آیپی محدود کند. در صورتی که کاربر با محدودیت مواجه نشده باشد، پردازش درخواست باید توسط next
صورت گیرد. در غیر اینصورت، کد پاسخ باید به 429
تغییر کند، مقدار هدر Content-Type
باید برابر با application/json
قرار داده شود و بدنهی پاسخ بهصورت زیر باشد:
{"error": "too many requests"}
تابع ByAppKey
امضای این تابع مشابه تابع ByIp
است.
این تابع را طوری پیادهسازی کنید که درخواستها را براساس مقدار هدر X-App-Key
موجود در درخواست محدود کند. اگر مقدار این هدر در جدول app_keys
وجود نداشته باشد، محدودیت نباید اعمال شود. در غیر اینصورت، محدودیت باید اعمال شود. اگر کاربر با محدودیت مواجه شده باشد، پاسخ باید مشابه پاسخ مورد انتظار برای تابع ByIp
باشد.
تضمین میشود که هنگام استفاده از این تابع، هدر X-App-Key
در درخواست موجود است.
ترکیب rate limiter ها
ممکن است بخواهیم rate limiter ها را ترکیب کنیم. اگر از توابع ByIp
و ByAppKey
در کنار یکدیگر استفاده شود، محدودیت باید هم براساس آیپی و هم براساس مقدار هدر X-App-Key
اعمال شود. مثلاً اگر مقدار tokenBucketSize
برابر با ۵ باشد و ۵ درخواست پیاپی با آیپیهای مختلف، اما با X-App-Key
یکسان (بهطوری که در جدول app_keys
موجود باشد) ارسال کنیم، باید با محدودیت مواجه شویم. همچنین اگر این درخواستها را با آیپی یکسان، اما با X-App-Key
های متفاوت (بهطوری که در جدول app_keys
موجود باشند) ارسال کنیم، باز هم باید با محدودیت مواجه شویم.
نکات
- نیازی به persistent بودن اطلاعات مربوط به rate limiter ها نیست (با خاتمهی برنامه، دادههای مربوط به rate limiter ها میتوانند از بین بروند).
- شما تنها مجاز به اعمال تغییرات در پوشهی
limiters
هستید. - در صورت نیاز، میتوانید فایلهای جدیدی در پوشهی
limiters
تعریف کنید.
آنچه باید آپلود کنید
پس از پیادهسازی موارد خواستهشده، پوشهی limiters
را زیپ کرده و آپلود کنید.
ارسال پاسخ برای این سؤال