• Состояние в программировании означает состояние системы, компонента или приложения в определенный момент времени.
• Понимание состояния и управление им важно для создания интерактивных и динамичных веб-приложений.
• Шаблоны проектирования, протоколы, брандмауэры и функции могут быть с сохранением состояния или без него.
• В статье объяснено, что такое состояние, а также архитектуры с сохранением состояния и без сохранения состояния с некоторыми аналогиями.
• Архитектура с отслеживанием состояния не является отказоустойчивой и масштабируемой, так как нагрузка на разных официантов распределяется неравномерно.
• Архитектура без учета состояния решает многие из этих проблем, сохраняя информацию о состоянии за пределами сервера.
• Данные о состоянии обычно хранятся в отдельной базе данных, доступной для всех серверов, создавая отказоустойчивую и масштабируемую архитектуру.
В программировании «состояние» (state) — это состояние системы, компонента или приложения в определённый момент времени.
В качестве простого примера: если вы совершаете покупки на amazon.com, то состояние — это то, вошли ли вы в систему или есть ли у вас что-то в корзине.
Состояние — это данные, которые хранятся и используются для отслеживания текущего состояния приложения. Понимание состояния и управление им крайне важны для создания интерактивных и динамичных веб-приложений.
Понятие «состояния» пересекает множество границ в архитектуре. Шаблоны проектирования (например, REST и GraphQL), протоколы (например, HTTP и TCP), брандмауэры и функции могут быть с сохранением состояния или без него. Но основополагающий принцип «состояния», объединяющий все эти области, остаётся неизменным.
В этой статье объясняется, что такое состояние. В ней также объясняется, что такое архитектура с сохранением состояния(stateful) и без сохранения состояния(stateless), приводятся некоторые аналогии, а также преимущества и недостатки обеих архитектур.
Что такое архитектура с сохранением состояния? What is Stateful Architecture?
Представьте, что вы идёте в ресторан, где подают пиццу, чтобы перекусить. В этом ресторане работает только один официант, и он подробно записывает номер вашего столика, что вы заказали, ваши предпочтения, основанные на предыдущих заказах, например, какой вид теста для пиццы вам нравится или на какие начинки у вас аллергия, и так далее.
Вся эта информация, которую официант записывает в блокнот, — это состояние клиента. Только официант, который вас обслуживает, имеет доступ к этой информации. Если вы хотите внести изменения в свой заказ или узнать, как он готовится, вам нужно обратиться к тому же официанту, который принял ваш заказ. Но поскольку официант только один, это не проблема.
Теперь предположим, что в ресторане становится оживлённее. Ваш официант должен обслуживать других гостей, поэтому на работу вызывают ещё официантов. Теперь вы хотите проверить статус своего заказа и внести в него небольшое изменение — обычную корочку вместо сырной. Единственный доступный официант отличается от того, кто изначально принимал ваш заказ.
У этого нового официанта нет информации о вашем заказе, то есть о вашем состоянии. Естественно, он не сможет проверить статус вашего заказа или внести в него изменения. Ресторан, который работает по такому принципу, где только официант, который изначально принял ваш заказ, может сообщать вам о его статусе или вносить в него изменения, использует дизайн с отслеживанием состояния.
Аналогичным образом, в приложении с отслеживанием состояния будет сервер, который запоминает данные клиентов (то есть их состояние). Все последующие запросы будут направляться на один и тот же сервер с помощью балансировщика нагрузки с поддержкой постоянных сеансов. Таким образом, сервер всегда знает о клиенте.
На схеме ниже показаны два разных пользователя, пытающихся получить доступ к веб-серверу через балансировщик нагрузки. Поскольку состояние приложения сохраняется на серверах, пользователи всегда должны направляться на один и тот же сервер для каждого запроса, чтобы сохранить состояние.
Привязка к сеансу (Sticky sessions - липкая сессия)— это конфигурация, которая позволяет балансировщику нагрузки последовательно направлять запросы пользователя на один и тот же внутренний сервер в течение всего сеанса. Это отличается от традиционной балансировки нагрузки, при которой запросы пользователя могут направляться на любой доступный внутренний сервер по круговой схеме или по другому принципу распределения нагрузки.
В чём проблема архитектуры с отслеживанием состояния? Представьте себе ресторан, работающий по такому принципу. Хотя это может быть идеальным и простым в реализации решением для небольшого семейного ресторана, в котором всего несколько посетителей, такая конструкция не отказоустойчива и не масштабируема.
Что произойдёт, если у официанта, принявшего заказ клиента, возникнет срочная необходимость уйти? Вся информация об этом заказе также уйдёт вместе с этим официантом. Это испортит впечатление клиента, поскольку любой новый официант, которого приведут на замену старому, не будет знать о предыдущих заказах. Такая система не отказоустойчива.
Кроме того, необходимость распределять заказы таким образом, чтобы один и тот же клиент мог говорить только с одним и тем же официантом, означает, что нагрузка на разных официантов распределяется неравномерно. Некоторые официанты будут перегружены заказами, если у вас есть очень требовательный клиент, который постоянно что-то меняет или добавляет в свой заказ. Некоторым другим официантам будет нечего делать, и они не смогут прийти на помощь. Опять же, это не масштабируемая система.
Аналогичным образом, хранение данных о состоянии для разных клиентов на разных серверах не является отказоустойчивым и не масштабируется. Сбой сервера приведёт к потере данных о состоянии. Таким образом, если пользователь вошёл в систему и собирается оформить крупный заказ, например, на Amazon.com, он будет вынужден повторно пройти аутентификацию, а его корзина будет пуста. Ему придётся снова войти в систему и заполнить корзину с нуля, что ухудшит пользовательский опыт.
Масштабируемость также будет сложно обеспечить в периоды пиковой нагрузки, например в Чёрную пятницу, при использовании дизайна с отслеживанием состояния. Новые серверы будут добавляться в группу автоматического масштабирования, но, поскольку включены постоянные сеансы, клиенты будут перенаправляться на один и тот же сервер, что приведёт к его перегрузке и может увеличить время отклика, ухудшив пользовательский опыт.
Архитектуры без сохранения состояния решают многие из этих проблем.
Что такое архитектура без состояния? What is Stateless Architecture?
«Архитектура без сохранения состояния statless» — неоднозначный термин, поскольку он подразумевает, что система не имеет состояния. Однако архитектура без сохранения состояния не означает, что информация о состоянии не сохраняется. Это просто означает, что информация о состоянии хранится вне сервера. Таким образом, отсутствие состояния относится только к серверу.
Возвращаясь к аналогии с рестораном, можно сказать, что официанты в stateless ресторане обладают идеальной забывчивой(forgetful) памятью. Они не узнают старых клиентов и не могут вспомнить, что вы заказали или как вам нравится ваша пицца. Они просто записывают заказы клиентов в отдельную систему, например, на компьютер, к которому имеют доступ все официанты. Затем они могут вернуться к компьютеру, чтобы получить информацию о заказе и внести в него необходимые изменения.
Сохраняя «состояние» заказа клиента в центральной системе, доступной другим официантам, любой официант может обслужить любого клиента.
В архитектуре без сохранения состояния HTTP-запросы от клиента могут быть отправлены на любой из серверов.
Состояние обычно хранится в отдельной базе данных, доступной для всех серверов. Это обеспечивает отказоустойчивость и масштабируемость архитектуры, поскольку веб-серверы можно добавлять или удалять по мере необходимости, не затрагивая данные о состоянии.
Нагрузка также будет равномерно распределена между всеми серверами, поскольку балансировщику нагрузки не потребуется конфигурация «закреплённого сеанса» для перенаправления одних и тех же клиентов на одни и те же серверы.
На схеме ниже показаны два разных пользователя, пытающихся получить доступ к веб-серверу через балансировщик нагрузки. Поскольку состояние приложения поддерживается отдельно от серверов, пользователи могут быть перенаправлены на любой из серверов, который затем получит информацию о состоянии из внешней базы данных, доступной обоим серверам.
Как правило, данные о состоянии хранятся в кэше, таком как Redis, хранилище данных в оперативной памяти. Хранение данных о состоянии в оперативной памяти сокращает время чтения и записи по сравнению с хранением на диске, как объясняется здесь.
Как объединить их
В этой статье описано, как работают веб-приложения с отслеживанием состояния и без него, а также их преимущества и недостатки. Но принцип отслеживания и отсутствия отслеживания состояния применим не только к веб-приложениям.
Если рассматривать сетевые протоколы в качестве примера, то HTTP — это протокол без сохранения состояния (stateless protocol). Это означает, что каждый HTTP-запрос от клиента к серверу независим и не содержит информации о предыдущих запросах или их контексте. Сервер обрабатывает каждый запрос как отдельную и изолированную транзакцию и не сохраняет информацию о состоянии клиента между запросами.
Состояние либо сохраняется на серверах (архитектура с сохранением состояния - stateful architecture), либо в отдельной базе данных за пределами серверов (архитектура без сохранения состояния - stateless architecture). Сам протокол HTTP не сохраняет состояние.
В отличие от HTTP, не поддерживающего состояние (stateless nature), протокол TCP ориентирован на соединение и поддерживает состояние ( connection-oriented and stateful). Он устанавливает соединение между двумя устройствами (обычно между клиентом и сервером) и поддерживает непрерывный канал связи до тех пор, пока соединение не будет разорвано.
Та же логика применима и к брандмауэрам(firewalls), которые могут быть с отслеживанием состояния или без него.
В AWS группа безопасности — это виртуальный брандмауэр, который контролирует входящий и исходящий трафик для виртуальных машин или инстансов в облачной среде. Группы безопасности поддерживают состояние Security groups are stateful. Когда вы разрешаете определенный входящий поток трафика, автоматически разрешается и соответствующий исходящий поток трафика. Другими словами, отслеживается состояние подключения.
Списки управления доступом к сети (Network Access Control Lists - NACL) используются для управления входящим и исходящим трафиком на уровне подсети в AWS. NACL не сохраняют состояние NACLs are stateless. Это означает, что вы должны явно задавать правила как для входящего, так и для исходящего трафика.
В отличие от групп безопасности, где ответный трафик автоматически разрешён при разрешении входящего трафика, NACL требуют определения отдельных правил для входящего и исходящего трафика.
Функции и шаблоны проектирования также могут быть с сохранением состояния(stateful) или без сохранения состояния(stateless).
Ключевой принцип, лежащий в основе системы с отслеживанием состояния, заключается в том, что она обладает идеальной памятью или знаниями о предыдущих вызовах или запросах, в то время как система без отслеживания состояния не обладает памятью или знаниями о предыдущих вызовах или запросах.
Надеюсь, теперь вы хорошо понимаете, как работают приложения с отслеживанием состояния и без него, и можете решить, какой вариант лучше подходит для ваших приложений.