В Modal наши бессерверные вычисления обеспечивают работу инференса реального времени, обучения и пакетных заданий, автоматически масштабируясь в зависимости от спроса. Песочницы (Sandboxes) предлагают другую модель — контейнеры, жизненным циклом которых вы управляете явно. Растущее число рабочих нагрузок требует чего-то среднего: автомасштабируемых бессерверных вычислений, сохраняющих непрерывность между запросами. Рассмотрите модель преобразования речи в текст с состоянием декодера для аудиопотока, голосового агента, ведущего диалог, или многопользовательскую игру. Для таких нагрузок пользователи должны возвращаться к одному и тому же контейнеру при каждом переподключении на протяжении всей своей сессии.
Мы недавно запустили Sticky Sessions, созданные на базе наших низколатентных Modal Servers. Запросы каждого сеанса попадают в один и тот же контейнер. Чтобы использовать Sticky Sessions, просто создайте Modal Server с декоратором @modal.sessioned() и запустите сеансы с помощью SDK или HTTP API:
Бессерверные вычисления с сильной привязкой
Modal уже некоторое время поддерживает WebSockets через Web Functions. Однако WebSocket-соединение привязано к «входу» (input) функции, а не к контейнеру — если соединение обрывается, при переподключении создается новый вход, который может попасть на другой контейнер.
Веб-интерфейсы с сохранением состояния, такие как Gradio и Streamlit, представляют собой рабочие нагрузки, которым требуются сильные гарантии привязки между запросами и бэкенд-контейнерами. Каждый запрос должен доходить до процесса, хранящего состояние пользователя. Одним из антипаттернов-обходных путей является установка max_containers=1, что гарантирует привязку за счет полного отказа от масштабирования.
Modal Servers уже предоставляют более мягкую форму привязки: запросы с одинаковым заголовком Modal-Affinity-Routing-Key маршрутизируются в один и тот же контейнер по принципу «лучших усилий» (best-effort). Контейнер все равно может быть уменьшен (scale down) или заменен в любой момент, после чего будущие запросы будут направлены в другой контейнер.
Sticky Sessions предоставляют более сильные гарантии маршрутизации, гарантируя, что все запросы в рамках одного сеанса попадают в один и тот же контейнер.
Modal Servers предоставили нам фундамент
Sticky Sessions базируются на инфраструктуре, которую мы разработали для Modal Servers. В основе этой инфраструктуры лежит наш собственный безгосударственный (stateless) прокси-сервер (fprs). Прокси обеспечивает низколатентную маршрутизацию и балансировку нагрузки, используя кэшируемое в памяти состояние маршрутизации, согласованное с долговечным хранилищем. Servers уже предоставляют нам способ маршрутизации HTTP-трафика в контейнер, управления жизненным циклом контейнеров и масштабирования пула в зависимости от спроса.
Для Sticky Sessions потребовались три вещи, которые не обеспечивала текущая маршрутизация на уровне запросов:
- Фиксированная маршрутизация: Каждый запрос в сеансе доходит до одного и того же контейнера.
- Жизненный цикл сеанса: Хост контейнера отслеживает, какие запросы принадлежат каким сеансам, и определяет, когда каждый сеанс становится неактивным.
- Автомасштабирование на основе сеансов: Пул контейнеров масштабируется в зависимости от количества активных сеансов, а не запросов.
Делаем бессерверную инфраструктуру осведомленной о сеансах
С точки зрения клиента, Sticky Session работает как труба (pipe). Как только клиент создает сеанс, каждый последующий запрос для этого сеанса будет направляться в тот же контейнер.
Это может показаться простым, но бессерверная инфраструктура Modal была создана и оптимизирована для противоположной идеи: что отдельные запросы независимы. Рассматривая Modal Servers с точки зрения сеансов (а не просто запросов), нам пришлось заново осмыслить авторизацию, балансировку нагрузки и автомасштабирование на основе фундаментальных принципов.
Авторизация
Modal Servers по умолчанию требуют прокси-токены (Proxy Tokens). Чтобы делиться Sticky Sessions, вам не нужно отключать аутентификацию или передавать свой Proxy Token.
Вместо этого каждый запрос sessions.start() возвращает подписанный токен сеанса, предоставляющий доступ к этому сеансу. Обмен этим токеном между клиентами позволяет нескольким участникам получить доступ к одному и тому же состоянию в комнате, игре или совместном приложении.
Поддержание маппинга «сеанс-контейнер» в прокси потребовало бы обеспечения согласованности этого маппинга при перезапусках и между несколькими репликами. Чтобы избежать этого, мы кодируем метаданные маршрутизации прямо в токен. Наши прокси проверяют токен и маршрутизируют запросы к контейнеру, удерживающему сеанс.
Балансировка нагрузки
Поскольку мы не храните состояние сеанса в прокси, авторитетное представление (authoritative view) о состоянии сеанса существует только на хосте, которому принадлежит сеанс. Это означает, что балансировщик нагрузки не может иметь мгновенного глобального представления о доступной емкости.
Для обнаружения доступной емкости наши балансировщики нагрузки периодически опрашивают контейнеры для получения снимка (snapshot) их доступной параллельности. Затем балансировщики нагрузки используют комбинацию недавних решений по маршрутизации и опрошенных снимков для выбора контейнера. Это равномерно распределяет сеансы по доступным контейнерам, минимизируя при этом накладные расходы на запросы к контейнерам, исчерпавшим свою емкость.
Автомасштабирование
Modal Servers автоматически масштабируются по объему запросов, стремясь достичь целевого показателя параллельности запросов на один контейнер. Автомасштабировщик, управляемый запросами, предполагает, что трафик запросов может быть равномерно перераспределен по обслуживающему пулу контейнеров. Эта модель хорошо работает для stateless Servers. Однако Sticky Sessions ведут себя иначе: трафик сеанса не подлежит перемещению. Трафик каждого сеанса должен попадать в один и тот же контейнер, даже если объем трафика различается между сеансами.
Это побудило сделать сеансы единицей параллельности, подобно Modal Functions с входами. Контейнер может быть настроен на одновременный запуск 1 или более сеансов. Когда параллельность исчерпывается, новые сеансы ждут в очереди завершения существующих сеансов или готовности нового контейнера. Автомасштабировщик непрерывно отслеживает количество активных сеансов и очередь запросов, чтобы принимать решения о масштабировании, которые должным образом изменяют размер вычислительного пула.
Что открывают Sticky Sessions
Сильные гарантии маршрутизации и жизненного цикла Sticky Sessions поверх Servers обеспечивают первоклассную поддержку нового набора приложений на Modal:
Низколатентные голосовые агенты: Modal Phonon Voice Bot запускает агента с преобразованием текста в речь Gradium Phonon поверх WebRTC. Каждый вызов представляет собой Sticky Session, привязанную к контейнеру, поэтому WebRTC-сигнализация достигает контейнера, удерживающего одноранговое соединение (peer connection). Сеанс поддерживает контейнер в активном состоянии, пока аудиопоток проходит через WebRTC.
Общие комнаты: Наш пример чат-комнаты с поддержкой сеансов закрепляет за каждой чат-комнатой Sticky Session. Каждый клиент, подключающийся с токеном сеанса, маршрутизируется в один и тот же контейнер. Сообщения каждой комнаты транслируются всем участникам в комнате. Клиенты могут отключаться и переподключаться к той же комнате в течение всего времени жизни сеанса чат-комнаты.
Игры: Игровые приложения хранят состояние в памяти для поддержания непрерывности и снижения задержек (lag). Sticky Sessions поддерживают как сохранение прогресса, так и хостинг одновременных комнат игроков.
Смелый мир с поддержкой сеансов (sticky world)
В Modal мы любим использовать Modal. В наших поисках бесконечного масштабирования и передовой производительности мы обнаружили, что играем в (множество) Curvytron. И, конечно же, мы размещаем наш собственный быстрый (никаких больше отговорок про задержку ввода!) деплой us-east на Modal Servers поверх Sticky Sessions.
Как и многие многопользовательские игры, Curvytron предлагает игрокам находиться в общей комнате и соревноваться друг с другом в реальном времени. С помощью Sticky Sessions игроки могут создавать комнаты, делиться ссылкой на игру и играть вместе! Modal автоматически масштабируется в зависимости от количества активных комнат.
Попробуйте здесь!
Особая благодарность Клаудии Чжу, Ричарду Гонгу, Акшату Бубне, Майклу Васкому и Бену Шабабо за помощь в разработке этой функции!
Если вам интересно создавать базовую инфраструктуру для программного обеспечения нового поколения, мы ведём наем.












