Почему сессия это сложно, и при чем тут токены
Привет, коллеги. Сегодня вкатываемся в, пожалуй, самую базовую, но от этого не менее холиварную тему -- аутентификацию. Точнее, в то, что происходит после того, как пользователь ввел логин и пароль. Как система вообще понимает, что следующий запрос от того же Васи, а не от самозванца?
Казалось бы, чего тут сложного? Но дьявол, как обычно, в архитектуре.
🐟 HTTP - это золотая, но рыбка
HTTP - протокол без состояния. Он как аквариумная рыбка: получил запрос, обработал, отдал ответ и всё, сразу забыл. Каждый новый запрос для сервера чистый лист.
📕 Проблема: как построить stateful-взаимодействие (личный кабинет, корзину, историю операций) поверх stateless-протокола?
📝Решение в лоб: Сессия на сервере
Логика простая:
1. Вася логинится.
2. Сервер генерирует длинную случайную строку - Session ID:
s3ss10n_vAsYa_12345.3. Сервер сохраняет у себя в памяти (или в БД) объект:
{ "s3ss10n_vAsYa_12345": { userId: 451, role: "user", cart: [...] } }.4. Клиенту отдает этот Session ID (обычно в куках).
5. Клиент с каждым запросом присылает Session ID.
6. Сервер ищет у себя этот ID и «вспоминает» Васю.
Это называется аутентификация с хранением состояния
Для аналитика это выглядит идеально:
▫️ Сервер всё контролирует.
▫️ Захотел разлогинить Васю — просто удалил запись из хранилища сессий.
▫️ В сессии можно копить контекст (шаги оформления заказа, временные настройки фильтров).
Но давайте наденем шляпу архитектора и посмотрим, что будет под нагрузкой.
♦️Проблема "Липкой сессии"
Представьте: у нас не один сервер, а три (потому что Вася такой не один, их миллионы). Запросы распределяет балансировщик.
Вася логинился на Сервере №1. Его сессия
s3ss10n_vAsYa_12345 лежит в оперативке Сервера №1.Следующий запрос Васи балансировщик отправляет на Сервер №2.
Сервер №2 смотрит в свою память: «Не знаю я никакого
s3ss10n_vAsYa_12345, ты кто?». Васю выкидывает на логин.Это называется Липкая сессия — мы вынуждены настраивать балансировщик так, чтобы запросы одного пользователя всегда падали на один и тот же сервер.
❓Чем это плохо?
🔅 Отказоустойчивость: Упал Сервер №1 - все Васи, привязанные к нему, теряют сессии (корзины, незавершенные заказы). Пользовательский опыт испорчен.
🔅 Масштабирование: Добавили новый Сервер №4. Часть пользователей ребалансируется на него, теряя сессии, потому что их родной сервер не догадывается, что они ушли.
🔅 Неравномерность нагрузки: Если на Сервер №1 приземлился активный юзер, который генерит 1000 запросов в минуту, а на Сервере №2 сидят спящие, то балансировка летит к чертям.
Это решение не масштабируется. Да, можно вынести сессии в Redis/Memcached. Но тогда каждый запрос требует сетевого похода в хранилище. Задержка растет. Архитектура усложняется.