Rate Limiting — первая линия защиты API от L7-атак, брутфорса и парсинга. Без rate limiting один клиент может положить весь сервис. С ним — получит 429 Too Many Requests и подождёт.
Стратегии Rate Limiting
Fixed Window
N запросов за период. Проблема: burst на границе окон.
Sliding Window
Скользящее окно — лучше для защиты, но требует больше памяти.
Token Bucket ✓
Токены накапливаются, тратятся на запросы. Рекомендуется для API — позволяет burst, ограничивает sustained load.
Nginx
http {
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=auth:10m rate=1r/s;
}
server {
location /api/ {
limit_req zone=api burst=20 nodelay;
limit_req_status 429;
}
location /api/auth/ {
limit_req zone=auth burst=5;
limit_req_status 429;
}
}
Node.js
const rateLimit = require('express-rate-limit');
const RedisStore = require('rate-limit-redis');
const apiLimiter = rateLimit({
store: new RedisStore({ client: redis }),
windowMs: 60 * 1000,
max: 100,
standardHeaders: true,
keyGenerator: (req) => req.headers['x-api-key'] || req.ip
});
const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5,
skipSuccessfulRequests: true
});
app.use('/api/', apiLimiter);
app.use('/api/auth/login', authLimiter);
Python
from flask import Flask
from flask_limiter import Limiter
app = Flask(__name__)
limiter = Limiter(app, key_func=get_remote_address,
storage_uri='redis://localhost:6379')
@app.route('/api/data')
@limiter.limit('100/minute')
def get_data():
return {'data': '...'}
@app.route('/api/auth/login', methods=['POST'])
@limiter.limit('5/15 minutes')
def login():
return {'token': '...'}
HTTP Headers
HTTP/1.1 429 Too Many Requests
Retry-After: 60
RateLimit-Limit: 100
RateLimit-Remaining: 0
{"error": "Rate limit exceeded"}