В веб-системе запрос пользователя может попасть на любой экземпляр сервиса. Какое архитектурное свойство позволяет масштабировать сервис без привязки сессии к конкретному экземпляру?
Это свойство называется statelessness, или отсутствие серверного состояния сессии между запросами. Каждый запрос должен содержать всё необходимое для обработки либо ссылаться на внешнее хранилище состояния, доступное любому экземпляру сервиса. Поэтому балансировщик может направить следующий запрос на другой экземпляр без потери контекста.
Такой подход является одним из ограничений стиля REST и в целом соответствует практике построения горизонтально масштабируемых веб-систем. Он решает проблему, возникающую при добавлении нескольких экземпляров приложения: состояние, сохранённое только в памяти одного процесса, становится недоступным другим экземплярам.
Отказ от локального состояния также упрощает замену, перезапуск и автоматическое масштабирование экземпляров. Система меньше зависит от конкретного узла, что особенно важно в распределённой среде.
Если экземпляр хранит сессию пользователя только в своей памяти, последующий запрос должен попасть на тот же экземпляр. Для этого применяют привязку сессии к узлу, но она ограничивает перераспределение нагрузки и усложняет отказоустойчивость.
При падении узла локальные сессии теряются. При масштабировании или уменьшении числа экземпляров балансировщик не может свободно распределять запросы, а нагрузка между узлами может стать неравномерной.
В stateless-сервисе результат обработки запроса определяется самим запросом, доступными сервису постоянными данными и его конфигурацией, а не предыдущим обращением именно к этому экземпляру. Контекст пользователя обычно передают в запросе через токен или идентификатор, а изменяемое состояние размещают во внешнем хранилище.
Есть два распространённых варианта. Токен может содержать необходимые утверждения и проверяться каждым экземпляром. Либо запрос содержит идентификатор сессии, по которому любой экземпляр обращается к общему хранилищу сессий.
Первый вариант уменьшает число обращений к хранилищу, но усложняет отзыв и изменение уже выданных токенов. Второй упрощает централизованное управление сессиями, но добавляет сетевую задержку, зависимость от доступности хранилища и необходимость продумать срок жизни и очистку данных.
Statelessness не означает отсутствия состояния вообще. Бизнес-состояние заказов, платежей и прав доступа всё равно где-то хранится. Требование относится к отсутствию необходимого для продолжения диалога состояния исключительно внутри конкретного экземпляра сервиса.
Липкие сессии являются компромиссом, а не полноценным решением: они позволяют использовать локальное состояние, но ухудшают балансировку, усложняют отказ при недоступности узла и препятствуют свободному масштабированию. Внешнее хранилище тоже не устраняет все проблемы автоматически: нужно учитывать его репликацию, согласованность, отказ и защиту данных.
Интернет-магазин запустили в нескольких экземплярах. Сначала корзина и данные входа хранились в памяти приложения, поэтому после перехода пользователя на другой экземпляр корзина исчезала.
Рассматривались три варианта. Липкая маршрутизация почти не требовала изменений, но создавала неравномерную нагрузку и делала отказ узла заметным для пользователей. Репликация локальной памяти между экземплярами сохраняла состояние, но добавляла сложный механизм синхронизации и новые задержки. Перенос пользовательских сессий и корзины во внешнее хранилище позволил любому экземпляру обработать запрос, но потребовал мониторинга и настройки отказоустойчивости хранилища.
Выбрали третий вариант: экземпляры оставили без обязательного состояния сессии, а долговечные данные разместили в общем хранилище. В результате экземпляры стали взаимозаменяемыми, балансировщик получил возможность свободно перераспределять нагрузку, а перезапуск отдельного узла перестал требовать повторного входа пользователя. При этом доступность внешнего хранилища сделали отдельным объектом мониторинга и резервирования.
Нет. Идентификатор сам по себе не делает систему stateless. Если обработка зависит от данных, доступных только локальной памяти конкретного экземпляра, свойство не выполнено. Идентификатор должен указывать на состояние во внешнем общем хранилище либо сопровождаться достаточными данными для обработки запроса.
Даже самодостаточный токен может требовать серверной проверки: например, для немедленного отзыва, проверки версии учётной записи или актуального статуса полномочий. Тогда система всё равно зависит от внешнего источника состояния. Корректный вывод состоит не в том, что токены всегда делают сервис stateless, а в том, что экземпляр не должен зависеть от локального состояния предыдущего запроса.
Оно не делает повторную доставку безопасной автоматически. Один и тот же запрос может быть обработан повторно, поэтому для операций с побочными эффектами нужны идемпотентность, уникальный идентификатор операции или механизм дедупликации. Отсутствие локальной сессии облегчает маршрутизацию повторного запроса, но корректность повторного выполнения остаётся отдельной задачей.