Rate limiting на edge: алгоритмы и реализация
Rate limiting защищает API от abuse и обеспечивает справедливое распределение ресурсов. На edge это сложнее — нужно координировать лимиты между десятками серверов с минимальной задержкой.
Зачем rate limiting на edge?
Традиционно rate limiting делается на бэкенде. Но у edge есть преимущества:
- Раннее отсечение — вредоносный трафик не доходит до origin
- Меньше latency — ответ 429 с ближайшего edge быстрее, чем с origin
- Географическая гранулярность — разные лимиты для разных регионов
Алгоритмы
Fixed Window
Простейший алгоритм: считаем запросы в фиксированном временном окне (минута, час).
window = current_time / window_size
count = increment(key + window)
if count > limit:
return 429
Проблема: burst на границе окна. Если лимит 100/мин, можно сделать 100 запросов в 0:59 и ещё 100 в 1:00.
Sliding Window Log
Храним timestamp каждого запроса, считаем за последние N секунд:
timestamps = get_timestamps(key)
timestamps = filter(t => t > now - window_size)
if len(timestamps) >= limit:
return 429
timestamps.append(now)
save(key, timestamps)
Проблема: O(N) память на клиента. При 1000 RPS и окне 1 минута — 60,000 timestamps.
Sliding Window Counter
Компромисс: используем два фиксированных окна и интерполируем:
prev_count = get(key + prev_window)
curr_count = get(key + curr_window)
weight = (now % window_size) / window_size
effective = prev_count * (1 - weight) + curr_count
if effective >= limit:
return 429
Точность 99.9% при O(1) памяти.
Token Bucket
Токены накапливаются с фиксированной скоростью, запрос потребляет токен:
tokens = min(max_tokens, tokens + rate * elapsed)
if tokens < 1:
return 429
tokens -= 1
Преимущество: позволяет burst до max_tokens, потом плавное ограничение.
Распределённый rate limiting
На edge сервера географически распределены. Варианты синхронизации:
| Подход | Консистентность | Latency |
|---|---|---|
| Centralized Redis | Strong | +10-50 мс |
| Per-node limits | Weak | 0 мс |
| Gossip protocol | Eventual | +1-5 мс |
Мы используем гибрид: локальный rate limiter + асинхронная синхронизация через gossip. При 10 edge-нодах и лимите 1000 RPS каждая нода получает ~100 RPS локального лимита + 10% buffer на неравномерность.
Конфигурация в EdgeByte
rate_limit:
- path: /api/v1/*
limit: 100
window: 1m
by: user_id
burst: 20
- path: /api/public/*
limit: 1000
window: 1m
by: ip
geo_multiplier:
RU: 1.5
US: 1.0
default: 0.5
Заключение
Для большинства случаев рекомендуем sliding window counter с token bucket для burst tolerance. Распределённая координация — через gossip с локальным fallback.
API Gateway в EdgeByte включает rate limiting из коробки с настройкой через YAML или Dashboard.