Как использовать Redis для хранения сессий и ограничения частоты запросов?
Подробный ответ
Хранение сессий
После входа пользователя приложение создаёт случайный идентификатор сессии, сохраняет в Redis связанные данные и отправляет идентификатор клиенту в защищённой cookie. При каждом запросе приложение по идентификатору получает сессию из Redis.
session_id = create_secure_random_token()
redis_client.hset(
f'session:{session_id}',
mapping={
'user_id': user.id,
'role': user.role,
},
)
redis_client.expire(f'session:{session_id}', 3600)Продление сессии
При активном использовании можно обновлять TTL сессии. Это называют скользящим сроком жизни: сессия продлевается после успешного запроса, но истекает при долгой неактивности.
redis_client.expire(f'session:{session_id}', 3600)Ограничение частоты запросов
Простой вариант использует ключ на пользователя или IP-адрес и счётчик запросов за фиксированный интервал. Redis выполняет увеличение счётчика атомарно.
def allow_request(client_id: str, limit: int = 100) -> bool:
key = f'ratelimit:{client_id}:minute'
current = redis_client.incr(key)
if current == 1:
redis_client.expire(key, 60)
return current <= limitЕсли за минуту число запросов превысит limit, API возвращает 429 Too Many Requests.
Недостаток фиксированного интервала
Фиксированный интервал допускает всплеск на границе минут. Пользователь может отправить 100 запросов в конце одной минуты и ещё 100 в начале следующей. Для более точного ограничения используют скользящий интервал или алгоритм «ведро с токенами».
Распределённая система
Redis должен быть общим для всех экземпляров API. Если каждый сервер считает запросы только в собственной памяти, клиент сможет обойти лимит, попадая на разные реплики. Для сложного алгоритма несколько действий Redis объединяют в Lua-скрипт, чтобы выполнить их атомарно.
Безопасность сессий
идентификатор сессии должен быть криптографически случайным;
cookie должна иметь флаги
HttpOnly,Secureи подходящийSameSite;сессию нужно удалять при выходе и при смене пароля;
не следует хранить в сессии больше данных, чем действительно нужно.
Как ответить на собеседовании
Для сессий храню в Redis данные по случайному идентификатору с TTL, а клиент получает только идентификатор в защищённой cookie. Для ограничения частоты использую общий Redis, атомарный INCR и EXPIRE. При высокой нагрузке выбираю ключ по пользователю или API-ключу, а для точного распределённого алгоритма использую атомарный Lua-скрипт или отдельный компонент ограничения запросов.
Оцени свой прогресс