Что значит Stateful Application

QuantumSoft
5 min readMar 21, 2024

Последнее время все чаще вижу, что многие инженеры не знают или не до конца понимают разницу между stateless и stateful приложениями. В своей статье мне хотелось бы разобраться в этом вопросе.

Начну с того, что я обнаружил немало неадекватных статей про stateless и stateful приложения. Так, на первой же странице поисковой выдачи по запросу “stateful application” почти все тексты неадекватны. Даже статья на Википедии ссылается на отсутствующее определение. Скорее всего, в этом и есть причина укоренившегося неверного представления о разнице между stateless и stateful приложениями.

В качестве примера неадекватной статьи предлагаю взглянуть на следующую: https://climstech.com/blog/stateful-and-stateless-applications/

В тексте сказано: “Stateful Application describes a structure that allows users to store, record, and return to already established information and processes over the internet.”

По непонятным причинам в качестве примера stateless приложения указан DNS.

Если предположить, что имеется имеется в виду протокол DNS, то это довольно странно, ведь даётся определение stateful/stateless приложений, а в качестве примеров используются протоколы. Если допустить, что имеются в виду DNS приложения, то налицо расхождение с реальностью: DNS сервера хранят, меняют и отдают информацию о доменных именах и их связях с IP адресами.

Я нашёл одну более или менее адекватную статью, однако отмечу, что она больше сфокусирована на stateless приложениях.

Теперь перейдем к сути вопроса. Разница между stateless и stateful приложениями заключается не в том, что они что-то где-то хранят или не хранят, а в характере хранимой информации. Stateful сервер хранит информацию о текущем состоянии (state) клиентского приложения (client). Обратите внимание, речь идет не о пользовательских данных (например, информация о залогиненном пользователе, тип запроса, данные запроса, и т.п.), но об информации о том, в каком состоянии сейчас клиентское приложение. Не дайте запутать себя! Пользователь (user), пользовательские данные (user data) и состояние клиента (client state) — это разные вещи.

Давайте уточним, о чем идет речь:

User — человек (или скрипт), взаимодействующий с системой.

User data — набор значений программных сущностей приложения. Это может быть тип запроса, значения параметров запроса, значения, связанные с этими параметрами, и т.п.

Client state — состояние клиентского приложения в клиент-серверной системе.

Чтобы разъяснить не совсем однозначное определение user data и client state, давайте рассмотрим следующий пример. Клиент-серверное приложение использует пользовательские сессии для авторизации пользователя и определения того, что нужно пользователю. Зачастую информация о сессии хранится где-то в базе данных на стороне сервера, а клиент хранит идентификатор сессии и с каждым запросом его передаёт. Можно запустить другое клиентское приложение и использовать ранее сохранённый идентификатор сессии для дальнейшей работы с сервером. Если сервер не увидит разницы, это означает, что у вас, скорее всего, stateless приложение, а не stateful. В этом примере сессия будят являться пользовательскими данными (user data), а не состоянием клиента (client state). Сервер хранит не информацию о состоянии клиента (client state), а пользовательскую информацию (user data), которую можно так или иначе передать между клиентами.

Разберем еще одно неудачное представление. Довольно часто в статьях заявляется, что stateful приложение зависит от предыдущих запросов (или транзакций — названия разнятся). Это более или менее верно в определённых случаях, но наличие/отсутствие предыдущих запросов не является фактором, определяющим stateful приложение. Не важно, каким путём было достигнуто текущее состояние клиента. Важно только то, что оно хранится и используется сервером. Здесь приведу вам простой пример stateful приложения, где нет ни одного запроса от клиента (после установления TCP соединения), — это сервер рассылки каких-либо одинаковых сообщений всем клиентам. В данном случае состоянием клиента, хранящимся на сервере, будет факт того, что клиент ожидает от сервера данных. Впрочем, надо отметить, что это частый случай, когда факт того, что клиент ожидает от сервера данных, хранится и используется сервером.

На мой взгляд, самый важный вывод из того, является ли приложение stateful или stateless, — это оценка сложности имплементации автоматического горизонтального масштабирования. Stateful приложение, как правило, сложно масштабировать горизонтально и тем более — автоматически. По своему опыту не могу назвать ни одного достаточно обобщённого (generic) решения, которое позволит легко масштабировать любое stateful приложение. В то время как stateless приложение, как правило, достаточно легко масштабируется. Есть готовое решение, которое подойдёт для всех stateless приложений, — балансировщик входящих запросов между запускаемыми серверами приложений. Тут сложность будет в основном в том, чтобы правильно подобрать уже существующие компоненты, из которых система будет собираться.

Не могу пройти мимо еще одного важного, на мой взгляд, аспекта. Следует понимать, что “диагноз” stateful или stateless зависит от точки зрения — уровня абстракции, с которого рассматривается приложение. Например, ВСЕ web-приложения ведут себя как stateful (даже если они могут быть названы stateless) в определённые моменты времени — в момент передачи данных по установленному TCP соединению.

Также замечу, что использование stateful протокола (TCP, например) не обязательно приводит к тому, что приложение будет stateful. Определение зависит от уровня абстракции, с которого мы смотрим на приложение, и от архитектуры с деталями имплементации. Верно и обратное — использование stateless протокола (UDP, например) не гарантирует, что приложение будет stateless. Повторю, это зависит от деталей реализации и точки зрения.

Имеет смысл упомянуть, что HTTP протокол тоже является stateful, но есть нюанс. Если в приложении будут использованы только GET/POST/PUT/etc., то протокол можно вполне охарактеризовать как stateless, кроме того без особых проблем получится создать stateless приложение. Но как только в приложении начинают использоваться WebSocket’ы, мы имеем дело со stateful протоколом и попытка создать stateless приложение оказывается сильно затруднена. Отдельно упомяну long polling — создание stateless приложения может оказаться довольно простым или непростым. Тут снова определение будет зависеть от уровня абстракции, с которого мы оцениваем приложение, и деталей реализации.

То же справедливо и для приложений — часть функционала, предоставляемого системой, может быть stateless, а часть — stateful.

Порой не удаётся сходу определить, каким является приложение — stateless или stateful. В таком случае… не надо определять вовсе. Главная ценность диагноза — лёгкость определения того, насколько сложно будет горизонтально масштабировать такое приложение. Другими словами, можно сэкономить время разработки, не тратя его на неверные решения. Если не удаётся легко определить характер приложения — поздравляю, вам попалась сложная система и придётся искать решение, как будто это stateful приложение.

Также не стоит думать, что StatefulSet предназначен исключительно для stateful приложений. Kubernetes даёт чёткое определение его назначению. А название… ну, какое выбрали.

Ну и немного личного. Порой встречаются совершенно неадекватные заявления типа “Any kind of online shop that remembers your cart is a stateful app”. Это не так. По наличию/отсутствию корзины нельзя определить, является ли приложение stateless или stateful. Нужно смотреть на детали имплементации.

Напоследок предложу идею конвертации stateful приложения в stateless. Можно попробовать преобразовать состояние клиента (client state) в пользовательские данные (user data), чтобы ими можно было свободно обмениваться между запущенными инстансами серверного ПО. Если это удалось сделать,то большую часть работы можно считать сделанной.

--

--