FA-TOOLS — Header Component
کدهای آماده Rate Limiting در Flask و FastAPI

کدهای آماده Rate Limiting در Flask و FastAPI

خلاصه سریع: چرا Rate Limiting مهم است؟

کدهای آماده Rate Limiting در Flask و FastAPI — تصویر 1
  • افزایش امنیت: جلوگیری از حملات DDoS و Brute Force.
  • بهینه‌سازی منابع: محافظت از سرور در برابر بار اضافی و مصرف بی‌رویه منابع.
  • عدالت در دسترسی: توزیع عادلانه دسترسی به API برای همه کاربران.
  • کنترل هزینه‌ها: کاهش هزینه‌های زیرساختی و پهنای باند.
  • پایداری سرویس: تضمین عملکرد پایدار و بدون وقفه برنامه.

در این مقاله، راهکارهای عملی و کدهای آماده برای پیاده‌سازی Rate Limiting در فریمورک‌های Flask و FastAPI را بررسی می‌کنیم تا API شما در برابر ترافیک بیش از حد محافظت شود.

فهرست مطالب

کدهای آماده Rate Limiting در Flask و FastAPI — تصویر 2

مقدمه‌ای بر Rate Limiting: چرا و چگونه؟

کدهای آماده Rate Limiting در Flask و FastAPI — تصویر 3

در دنیای پر سرعت وب امروز، محافظت از API‌ها در برابر سوء استفاده و ترافیک بیش از حد یک نیاز اساسی است. Rate Limiting دقیقاً همین کار را انجام می‌دهد: تعداد درخواست‌هایی که یک کاربر یا یک IP می‌تواند در یک بازه زمانی مشخص به سرور ارسال کند را محدود می‌کند.

تصور کنید یک ربات مخرب در حال تلاش برای حدس زدن رمز عبور کاربران شما است (Brute Force Attack) یا اینکه رقیبی می‌خواهد با ارسال میلیون‌ها درخواست، سرویس شما را از دسترس خارج کند (DDoS Attack). بدون Rate Limiting، سرور شما به سرعت دچار اضافه بار شده و سرویس‌دهی مختل می‌شود. حتی ترافیک بالای کاربران عادی اما پرتقاضا هم می‌تواند به سرور آسیب برساند و تجربه کاربری بقیه را از بین ببرد.

مزایای کلیدی Rate Limiting:

  • امنیت بالا: مقابله با حملات Brute Force، DDoS و Scrapping.
  • پایداری سرویس: تضمین عملکرد روان و قابل اعتماد API حتی در اوج بار.
  • مدیریت منابع: جلوگیری از مصرف بی‌رویه CPU، حافظه و پهنای باند سرور.
  • تجربه کاربری بهتر: حفظ کیفیت سرویس برای کاربران مجاز.
  • کنترل دسترسی: پیاده‌سازی مدل‌های دسترسی پله‌کانی (مثلاً کاربران VIP دسترسی بیشتری دارند).

برای پیاده‌سازی Rate Limiting، معمولاً از الگوریتم‌های مختلفی مثل Token Bucket، Leaky Bucket یا Fixed Window استفاده می‌شود. در فریمورک‌های Flask و FastAPI، این کار معمولاً با استفاده از Decorator‌ها یا Middleware‌ها انجام می‌شود که توسعه‌دهنده بتواند به راحتی محدودیت‌ها را اعمال کند.

پیاده‌سازی Rate Limiting در Flask

در Flask، پکیج `Flask-Limiter` بهترین و رایج‌ترین ابزار برای پیاده‌سازی Rate Limiting است. این پکیج انعطاف‌پذیری بالایی دارد و به شما اجازه می‌دهد تا محدودیت‌ها را به صورت سراسری، برای هر مسیر (Route) یا حتی برای هر کاربر تعیین کنید.

۱. نصب Flask-Limiter

pip install Flask-Limiter Flask-Limiter[redis] # اگر می‌خواهید از Redis برای ذخیره‌سازی استفاده کنید

۲. مثال پایه: محدودیت سراسری و محلی

در این مثال، یک محدودیت سراسری (Global) برای کل برنامه Flask و یک محدودیت خاص برای یک Route مشخص اعمال می‌کنیم.


from flask import Flask, request, jsonify
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address

app = Flask(__name__)

# ۱. راه‌اندازی Limiter با ذخیره‌سازی در حافظه (می‌توانید به Redis تغییر دهید)
# استفاده از `get_remote_address` برای شناسایی کاربر بر اساس IP
limiter = Limiter(
    get_remote_address,
    app=app,
    default_limits=["200 per day", "50 per hour"], # محدودیت سراسری پیش‌فرض
    storage_uri="memory://", # می‌توانید به "redis://localhost:6379" تغییر دهید
)

@app.route("/")
@limiter.limit("5 per minute") # محدودیت محلی: ۵ درخواست در دقیقه برای این مسیر
def index():
    return jsonify({"message": "Welcome to the limited API!"})

@app.route("/slow")
@limiter.limit("1 per 5 seconds") # محدودیت محلی سخت‌تر
def slow_endpoint():
    return jsonify({"message": "This endpoint is very slow!"})

@app.route("/unlimited")
@limiter.exempt # این مسیر از تمام محدودیت‌ها معاف است
def unlimited_endpoint():
    return jsonify({"message": "You can hit this as much as you want!"})

@app.route("/user_specific")
@limiter.limit("10 per minute", key_func=lambda: request.headers.get("X-API-KEY")) # محدودیت بر اساس هدر API Key
def user_specific_endpoint():
    api_key = request.headers.get("X-API-KEY", "No-API-Key")
    return jsonify({"message": f"Hello, {api_key}! Limited per API Key."})


if __name__ == "__main__":
    app.run(debug=True)
    

در کد بالا، ما یک محدودیت سراسری ۲۰0 درخواست در روز و ۵۰ درخواست در ساعت را تنظیم کرده‌ایم. همچنین، مسیر `/` به ۵ درخواست در دقیقه و مسیر `/slow` به ۱ درخواست در ۵ ثانیه محدود شده است. مسیر `/unlimited` کاملاً از Rate Limiting معاف است. نکته مهم در اینجا، استفاده از `get_remote_address` است که به صورت خودکار IP کاربر را برای اعمال محدودیت‌ها شناسایی می‌کند. برای محدودیت‌های پیچیده‌تر، مثلاً بر اساس API Key، می‌توانیم `key_func` را کاستومایز کنیم.

۳. شخصی‌سازی پاسخ خطا

وقتی کاربر به محدودیت می‌رسد، Flask-Limiter به صورت پیش‌فرض یک پاسخ `429 Too Many Requests` برمی‌گرداند. می‌توانید این پاسخ را شخصی‌سازی کنید:


from werkzeug.exceptions import HTTPException

@app.errorhandler(429)
def ratelimit_handler(e):
    # e.description شامل اطلاعات دقیق‌تر محدودیت است
    return jsonify(message=f"تعداد درخواست‌های شما زیاد است. لطفا {e.description} صبر کنید."), 429
    

این قطعه کد را بعد از تعریف `app` و `limiter` در فایل Flask خود اضافه کنید.

پیاده‌سازی Rate Limiting در FastAPI

FastAPI به خاطر معماری مدرن و استفاده از تایپ هینتینگ (Type Hinting) و Pydantic، تجربه توسعه بسیار خوبی ارائه می‌دهد. برای Rate Limiting در FastAPI، پکیج `FastAPI-Limiter` یک انتخاب عالی است.

۱. نصب FastAPI-Limiter

pip install fastapi-limiter[redis]

این پکیج به صورت پیش‌فرض به Redis نیاز دارد، پس مطمئن شوید که Redis روی سیستم شما نصب و فعال است. اگر Redis نصب نیست، می‌توانید از گزینه `memory://` استفاده کنید، اما Redis برای محیط پروداکشن توصیه می‌شود.

۲. مثال پایه: محدودیت با دکوراتور

در FastAPI، `FastAPI-Limiter` به سادگی با دکوراتور‌ها کار می‌کند.


import time
from fastapi import FastAPI, Request, HTTPException
from fastapi_limiter import FastAPILimiter
from fastapi_limiter.depends import RateLimiter
from redis.asyncio import Redis

app = FastAPI()

# تابع برای شناسایی کلید (مثلاً IP کاربر)
def custom_key_func(request: Request):
    # می‌توانید بر اساس IP، API Key (از هدر) یا ID کاربر محدودیت بگذارید
    return request.client.host

@app.on_event("startup")
async def startup():
    # راه‌اندازی FastAPILimiter با اتصال به Redis
    # برای دمو می‌توانید از "redis://localhost:6379/0" استفاده کنید
    # مطمئن شوید Redis Server در حال اجرا است
    redis_connection = Redis(host="localhost", port=6379, db=0, encoding="utf-8", decode_responses=True)
    await FastAPILimiter.init(redis_connection, prefix="fastapi-limiter", identifier=custom_key_func)
    print("FastAPI-Limiter initialized with Redis.")

@app.on_event("shutdown")
async def shutdown():
    # بستن اتصال Redis هنگام خاموش شدن برنامه
    await FastAPILimiter.close()
    print("FastAPI-Limiter connection closed.")

@app.get("/")
@RateLimiter(times=5, seconds=60) # ۵ درخواست در ۶۰ ثانیه
async def read_root(request: Request):
    return {"message": "Hello from limited endpoint!"}

@app.get("/items/{item_id}")
@RateLimiter(times=1, minutes=1) # ۱ درخواست در دقیقه
async def read_item(item_id: int, request: Request):
    return {"item_id": item_id, "message": "This item is rate-limited."}

@app.get("/unlimited")
async def unlimited_endpoint():
    return {"message": "This endpoint is not rate-limited."}

@app.get("/premium")
@RateLimiter(times=20, seconds=60, # محدودیت بالاتر برای کاربران ویژه
             key_func=lambda request: request.headers.get("X-Premium-User-ID", request.client.host)) # بر اساس ID کاربر ویژه یا IP
async def premium_endpoint(request: Request):
    user_id = request.headers.get("X-Premium-User-ID", "Guest")
    return {"message": f"Welcome, {user_id}! You have premium access with higher limits."}

# نحوه اجرای: uvicorn your_file_name:app --reload
    

در این مثال، FastAPILimiter در رویداد `startup` برنامه مقداردهی اولیه می‌شود. ما یک `custom_key_func` تعریف کرده‌ایم که IP کاربر را به عنوان شناسه اصلی برای Rate Limiting برمی‌گرداند. سپس با استفاده از دکوراتور `RateLimiter`، محدودیت‌ها را به مسیرهای مختلف اعمال می‌کنیم. همچنین یک مثال برای Rate Limiting بر اساس یک هدر سفارشی (مثل `X-Premium-User-ID`) آورده شده است.

۳. محدودیت سراسری (Global) در FastAPI

برای اعمال یک محدودیت سراسری در FastAPI، می‌توانید از Middleware استفاده کنید.


# ... (کدهای بالا، شامل app و FastAPILimiter.init) ...

# تعریف یک middleware برای اعمال محدودیت سراسری
@app.middleware("http")
async def global_rate_limit_middleware(request: Request, call_next):
    # این محدودیت برای تمام مسیرهایی که به صورت محلی محدود نشده‌اند اعمال می‌شود
    # یا به عنوان یک لایه اضافی روی مسیرهای محدود شده
    # مثال: ۱۰۰ درخواست در دقیقه برای تمام endpoint ها
    try:
        # اینجا می‌توانید logic پیچیده‌تری اضافه کنید
        # مثلاً فقط به درخواست‌های خاص محدودیت بدهید
        await RateLimiter(times=100, seconds=60)(request)
    except HTTPException as e:
        if e.status_code == 429:
            return JSONResponse(status_code=429, content={"message": "Too many requests. Please try again later."})
        raise
    
    response = await call_next(request)
    return response

# ... (ادامه endpoint ها) ...
    

این روش کمی پیچیده‌تر است، چرا که `FastAPI-Limiter` بیشتر روی دکوراتورها تمرکز دارد. معمولاً بهتر است محدودیت‌های سراسری را در سطح Reverse Proxy مثل Nginx یا Cloudflare پیاده‌سازی کنید و از `FastAPI-Limiter` برای محدودیت‌های دقیق‌تر و منطقی در سطح برنامه استفاده کنید.

تکنیک‌های پیشرفته Rate Limiting

علاوه بر محدودیت‌های ساده بر اساس IP، می‌توانید از تکنیک‌های پیشرفته‌تری هم استفاده کنید:

۱. Rate Limiting بر اساس شناسه کاربری (Authenticated User)

اگر کاربران شما احراز هویت شده‌اند، می‌توانید محدودیت‌ها را بر اساس ID کاربر اعمال کنید. این روش دقیق‌تر از IP است، چون چندین کاربر پشت یک NAT ممکن است یک IP مشترک داشته باشند.


# Flask (نیاز به دسترسی به ID کاربر احراز هویت شده دارد)
# فرض کنید user_id از flask_login یا JWT بدست می‌آید
@app.route("/protected")
@limiter.limit("10 per minute", key_func=lambda: current_user.id if current_user.is_authenticated else "anonymous")
def protected_route():
    # ...
    

# FastAPI (نیاز به Dependency Injection برای بدست آوردن کاربر احراز هویت شده)
from fastapi import Depends, Header

async def get_current_user_id(x_user_id: str = Header(..., alias="X-User-ID")):
    return x_user_id # در یک سناریوی واقعی، اینجا احراز هویت انجام می‌شود

@app.get("/secure")
@RateLimiter(times=10, seconds=60, key_func=lambda request: request.headers.get("X-User-ID"))
async def secure_endpoint(user_id: str = Depends(get_current_user_id)):
    return {"message": f"Hello, user {user_id}! You have secure access."}
    

۲. Rate Limiting بر اساس نقش کاربری (Role-Based)

می‌توانید برای نقش‌های کاربری مختلف (مثلاً Admin، Premium، Free) محدودیت‌های متفاوتی اعمال کنید.


# Flask (فرض کنید current_user.role در دسترس است)
@app.route("/tier-api")
@limiter.limit("10/minute", key_func=lambda: request.headers.get("X-User-Tier", "free"),
               override_defaults=False) # override_defaults=False prevents global limits from overriding
@limiter.limit("50/minute", key_func=lambda: request.headers.get("X-User-Tier", "free"),
               args_func=lambda: "premium", override_defaults=True)
def tiered_api():
    # این مثال کمی پیچیده است و نیاز به منطق دقیق‌تری دارد تا با هم تداخل نکند
    # یک روش ساده‌تر: یک decorator سفارشی بسازید
    user_tier = request.headers.get("X-User-Tier", "free")
    if user_tier == "premium":
        return jsonify({"message": "Premium user access"})
    return jsonify({"message": "Free user access"})
    

برای Flask، پیاده‌سازی محدودیت‌های نقش‌محور ممکن است نیاز به نوشتن یک Decorator سفارشی یا منطق پیچیده‌تری در `key_func` داشته باشد تا tier کاربر را تشخیص دهد و محدودیت مناسب را اعمال کند.


# FastAPI
from fastapi import Depends, Header

async def get_user_role(x_user_role: str = Header(default="free", alias="X-User-Role")):
    return x_user_role

@app.get("/role-based")
async def role_based_endpoint(user_role: str = Depends(get_user_role), request: Request = Depends(RateLimiter(times=5, seconds=60))):
    if user_role == "premium":
        # اگر کاربر premium بود، محدودیت را نادیده بگیرید یا محدودیت دیگری اعمال کنید
        await RateLimiter(times=50, seconds=60)(request) # اعمال محدودیت متفاوت به صورت پویا (کمی پیچیده است، معمولاً با یک if ساده انجام می‌شود)
        return {"message": "Premium access for premium role!"}
    return {"message": "Standard access for free role!"}

# یک روش بهتر برای FastAPI این است که RateLimiter را درون Depends بگذارید و منطق را در آن مدیریت کنید.
# یا چندین RateLimiter با override_defaults استفاده کنید.
    

در FastAPI، می‌توان با استفاده از `Depends` و `key_func` پویا، این کار را به شکلی تمیزتر انجام داد، اما ممکن است نیاز به یک dependency سفارشی داشته باشد که نقش کاربر را تشخیص داده و سپس بر اساس آن یک `RateLimiter` مناسب را اعمال کند.

مقایسه Rate Limiting در Flask و FastAPI

هر دو فریمورک Flask و FastAPI، ابزارهای قدرتمندی برای توسعه وب هستند و از پکیج‌های شخص ثالث برای Rate Limiting استفاده می‌کنند. در جدول زیر، یک مقایسه اجمالی بین نحوه پیاده‌سازی و ویژگی‌های آن‌ها آورده شده است:

ویژگی Flask (با Flask-Limiter) FastAPI (با FastAPI-Limiter)
پکیج اصلی Flask-Limiter FastAPI-Limiter
نحوه اعمال محدودیت دکوراتور (Decorator)، محدودیت سراسری دکوراتور (Decorator)، Dependency Injection
وابستگی ذخیره‌سازی حافظه، Redis، Memcached، MongoDB Redis (پیشنهاد شده)
شناسایی کلید (Key) `get_remote_address` یا `key_func` سفارشی `identifier` در `init` یا `key_func` در `RateLimiter`
پاسخ خطا HTTP 429، قابل شخصی‌سازی با `errorhandler` HTTP 429، قابل مدیریت در `middleware` یا `exception handler`
پیچیدگی پیاده‌سازی نسبتاً ساده برای موارد پایه، متوسط برای موارد پیشرفته ساده برای موارد پایه، استفاده از `Depends` نیاز به درک FastAPI دارد

بهترین شیوه‌ها و نکات کلیدی

پیاده‌سازی Rate Limiting فقط نوشتن چند خط کد نیست، بلکه نیاز به استراتژی و رعایت بهترین شیوه‌ها دارد:

  • شناسایی دقیق کاربر: فقط به IP اکتفا نکنید. برای کاربران لاگین شده، از ID کاربر استفاده کنید. برای API‌های عمومی، ترکیبی از IP و User-Agent می‌تواند کمک کند.
  • استفاده از سیستم ذخیره‌سازی بیرونی: برای برنامه‌هایی که در مقیاس بالا کار می‌کنند یا چندین Instance دارند، حتماً از Redis یا Memcached استفاده کنید تا وضعیت Rate Limiting بین تمام Instance‌ها هماهنگ باشد. استفاده از حافظه محلی (Memory) فقط برای توسعه و تست مناسب است.
  • تعیین محدودیت‌های معقول: محدودیت‌ها را بیش از حد سخت یا بیش از حد آزادانه قرار ندهید. به نیازهای واقعی کاربران و الگوهای ترافیک برنامه خود توجه کنید. آزمون و خطا در این زمینه اهمیت دارد.
  • اطلاع‌رسانی به کاربر: وقتی کاربر به محدودیت می‌رسد، پاسخ خطا (HTTP 429) را به همراه اطلاعات مفیدی مانند زمان انتظار تا درخواست بعدی (`Retry-After` Header) برگردانید. هر دو پکیج این Header را به صورت خودکار اضافه می‌کنند.
  • محدودیت‌های چندگانه: برای بخش‌های مختلف API، محدودیت‌های متفاوتی در نظر بگیرید. مثلاً برای ورود به سیستم (Login) محدودیت سخت‌تری (مثلاً ۵ درخواست در ۵ دقیقه) نسبت به مشاهده اطلاعات عمومی (مثلاً ۱۰۰ درخواست در دقیقه) داشته باشید.
  • Rate Limiting در سطوح مختلف: علاوه بر سطح برنامه، Rate Limiting را در سطح Reverse Proxy (مانند Nginx یا Cloudflare) نیز اعمال کنید. این کار به محافظت از سرور شما در برابر ترافیک مخرب قبل از رسیدن به برنامه کمک می‌کند.
  • مستثنی کردن مسیرهای خاص: برخی از مسیرها (مثل Health Check یا Webhook‌های خاص) ممکن است نیازی به Rate Limiting نداشته باشند. از قابلیت `exempt` استفاده کنید.
  • ثبت وقایع (Logging): درخواست‌هایی که به Rate Limit می‌رسند را ثبت کنید. این اطلاعات برای تحلیل الگوهای حمله و تنظیم دقیق‌تر محدودیت‌ها بسیار مفید است.

مشکلات رایج و راه‌حل‌ها

۱. تمام کاربران پشت یک NAT با یک IP دیده می‌شوند.

مشکل: در محیط‌های بزرگ یا شرکت‌ها، ممکن است ده‌ها یا صدها کاربر از طریق یک آدرس IP عمومی به سرویس شما دسترسی پیدا کنند. اگر Rate Limiting فقط بر اساس IP باشد، تمام این کاربران به سرعت به محدودیت می‌رسند.

راه‌حل:

  • برای کاربران احراز هویت شده، Rate Limiting را بر اساس ID کاربر پیاده‌سازی کنید.
  • اگر از Reverse Proxy (مثل Nginx) استفاده می‌کنید، مطمئن شوید که Header‌های `X-Forwarded-For` یا `X-Real-IP` به درستی تنظیم شده‌اند و برنامه شما از آن‌ها برای شناسایی IP اصلی استفاده می‌کند.
  • برای کاربران غیر احراز هویت شده، می‌توانید ترکیبی از IP و User-Agent یا Cookie‌های خاص را به عنوان کلید Rate Limiting در نظر بگیرید، البته این روش هم کاملاً بدون مشکل نیست.

۲. Rate Limiting در محیط Multi-Instance کار نمی‌کند.

مشکل: اگر برنامه شما روی چندین سرور یا چندین کانتینر (مثل Docker Swarm یا Kubernetes) اجرا می‌شود، استفاده از `memory://` به عنوان Backend ذخیره‌سازی، محدودیت‌ها را به درستی هماهنگ نمی‌کند. هر Instance، شمارنده درخواست‌های خود را دارد.

راه‌حل:

  • حتماً از Backend‌های ذخیره‌سازی متمرکز و خارجی مانند Redis یا Memcached استفاده کنید. این سیستم‌ها وضعیت Rate Limiting را بین تمام Instance‌ها به اشتراک می‌گذارند.
  • اطمینان حاصل کنید که تمام Instance‌های برنامه شما به یک سرویس Redis مشترک متصل هستند.

۳. مسدود شدن ناخواسته ربات‌های مفید (مثل ربات‌های موتور جستجو).

مشکل: گاهی اوقات ربات‌های موتورهای جستجو یا سایر سرویس‌های مفید، ممکن است تعداد درخواست‌های بالایی ارسال کنند و به اشتباه مسدود شوند.

راه‌حل:

  • ربات‌های موتور جستجوی معروف را با استفاده از User-Agent آن‌ها مستثنی کنید (Exempt). این کار را می‌توانید در `key_func` یا با یک Middleware انجام دهید.
  • می‌توانید برای این ربات‌ها، محدودیت‌های بالاتری در نظر بگیرید.
  • از فایل `robots.txt` برای راهنمایی ربات‌ها در مورد نحوه دسترسی به سایت خود استفاده کنید.

۴. عملکرد ضعیف به دلیل Overhead Rate Limiting.

مشکل: هرچند Rate Limiting برای محافظت از عملکرد سرور است، اما خود فرآیند بررسی و ذخیره درخواست‌ها می‌تواند Overhead ایجاد کند، به خصوص اگر سیستم ذخیره‌سازی کند باشد.

راه‌حل:

  • از Backend‌های ذخیره‌سازی با کارایی بالا مانند Redis استفاده کنید که بهینه شده برای عملیات خواندن/نوشتن سریع هستند.
  • Rate Limiting را در سطح Reverse Proxy نیز پیاده‌سازی کنید تا درخواست‌های مخرب قبل از رسیدن به برنامه شما فیلتر شوند و بار روی برنامه کمتر شود. این کار به بهره‌وریی بیشتر کمک می‌کند.
  • اگر Redis در همان سرور برنامه نیست، مطمئن شوید که تاخیر شبکه (Latency) بین برنامه و Redis کم باشد.

عیب‌یابی سریع (Troubleshooting)

در ادامه به چند مشکل رایج و راه‌حل سریع آن‌ها می‌پردازیم:

  1. مشکل: Rate Limiting کار نمی‌کند یا محدودیت‌ها اعمال نمی‌شوند.
    • بررسی کنید: آیا پکیج `Flask-Limiter` یا `FastAPI-Limiter` به درستی نصب شده است؟
    • بررسی کنید: آیا `Limiter` (Flask) یا `FastAPILimiter.init` (FastAPI) به درستی در ابتدای برنامه مقداردهی اولیه شده‌اند؟
    • بررسی کنید: آیا Decoratorهای `@limiter.limit` یا `@RateLimiter` روی مسیرهای مورد نظر اعمال شده‌اند؟
    • بررسی کنید: در FastAPI، آیا `await FastAPILimiter.init(…)` با `await` فراخوانی شده است؟
  2. مشکل: Redis (یا Memcached) متصل نمی‌شود یا خطا می‌دهد.
    • بررسی کنید: آیا سرویس Redis (یا Memcached) در حال اجرا است؟ `redis-cli ping` (برای Redis).
    • بررسی کنید: آدرس `storage_uri` (Flask) یا پارامتر `redis_connection` (FastAPI) صحیح است؟ پورت و هاست درست هستند؟
    • بررسی کنید: آیا پورت‌های مورد نیاز در فایروال سرور باز هستند؟ (معمولاً ۶۳۷۹ برای Redis).
  3. مشکل: کاربران پشت Reverse Proxy همیشه مسدود می‌شوند.
    • بررسی کنید: آیا Reverse Proxy شما (مثل Nginx) هدر‌های `X-Forwarded-For` یا `X-Real-IP` را به درستی به برنامه ارسال می‌کند؟
    • بررسی کنید: در Flask، آیا `get_remote_address` در `limiter` تنظیم شده است؟ (پیش‌فرض آن معمولاً این هدرها را بررسی می‌کند).
    • بررسی کنید: در FastAPI، آیا `custom_key_func` شما (در `FastAPILimiter.init`) به درستی از `request.client.host` یا هدرهای `X-Forwarded-For` استفاده می‌کند؟
  4. مشکل: پیام خطای `429 Too Many Requests` به خوبی نمایش داده نمی‌شود.
    • بررسی کنید: در Flask، آیا `app.errorhandler(429)` را برای شخصی‌سازی پیام خطا اضافه کرده‌اید؟
    • بررسی کنید: در FastAPI، می‌توانید یک `Exception Handler` سفارشی برای `HTTPException` با کد `429` اضافه کنید.
  5. مشکل: محدودیت‌ها برای کاربران لاگین شده و مهمان یکسان اعمال می‌شود.
    • بررسی کنید: برای کاربران لاگین شده، `key_func` را به گونه‌ای تنظیم کنید که از ID کاربر (مثلاً `current_user.id` در Flask یا از طریق `Depends` در FastAPI) استفاده کند.
    • بررسی کنید: مطمئن شوید که منطق برنامه برای تشخیص کاربر احراز هویت شده، درست است.

پرسش‌های متداول (FAQ)

۱. Rate Limiting دقیقاً چیست؟

Rate Limiting یک استراتژی برای محدود کردن تعداد درخواست‌هایی است که یک کاربر یا آدرس IP می‌تواند در یک بازه زمانی مشخص به یک سرور یا API ارسال کند. این کار به محافظت از سرور در برابر حملات، سوء استفاده و اطمینان از دسترسی عادلانه به منابع کمک می‌کند.

۲. آیا Rate Limiting جلوی حملات DDoS را می‌گیرد؟

Rate Limiting می‌تواند تا حد زیادی از سرور شما در برابر حملات DDoS لایه اپلیکیشن (Layer 7 DDoS) محافظت کند. این حملات معمولاً با ارسال تعداد زیادی درخواست معتبر به API باعث مصرف بی‌رویه منابع می‌شوند. اما برای مقابله با حملات DDoS در لایه‌های پایین‌تر (مانند حملات حجمی)، نیاز به راهکارهای پیشرفته‌تری مثل CDN‌ها و فایروال‌های سخت‌افزاری وجود دارد.

۳. بهترین مکان برای اعمال Rate Limiting کجاست؟

بهترین رویکرد، اعمال Rate Limiting در چندین لایه است:

  • Reverse Proxy (Nginx, Cloudflare): برای فیلتر کردن ترافیک مخرب در همان ابتدا و کاهش بار روی سرورهای اپلیکیشن.
  • سطح اپلیکیشن (Flask, FastAPI): برای اعمال محدودیت‌های دقیق‌تر و منطقی بر اساس نوع کاربر، نقش یا نوع API Call.

۴. چه الگوریتم‌هایی برای Rate Limiting وجود دارد؟

رایج‌ترین الگوریتم‌ها عبارتند از:

  • Fixed Window: ساده‌ترین روش که درخواست‌ها را در یک بازه زمانی ثابت (مثلاً ۱ دقیقه) می‌شمارد. مشکل آن “Burstiness” در مرزهای پنجره است.
  • Sliding Window Log: درخواست‌ها را در یک پنجره متحرک (مثل ۱ دقیقه گذشته) حساب می‌کند. دقیق‌تر است اما پیچیدگی ذخیره‌سازی بالاتری دارد.
  • Token Bucket: یک سطل با تعداد مشخصی توکن وجود دارد که با نرخ ثابتی پر می‌شود. هر درخواست یک توکن مصرف می‌کند. اگر سطل خالی باشد، درخواست رد می‌شود. این روش “Burstiness” را بهتر مدیریت می‌کند.
  • Leaky Bucket: شبیه Token Bucket است اما درخواست‌ها به جای توکن‌ها به یک صف با ظرفیت محدود اضافه می‌شوند و با نرخ ثابتی از آن خارج می‌شوند.

پکیج‌های Flask-Limiter و FastAPI-Limiter معمولاً از ترکیبی از این الگوریتم‌ها یا نسخه‌های بهینه شده آن‌ها استفاده می‌کنند.

Table of Contents

آخرین نوشته‌ها