Услуги Портфолио Контакты БлогНовости +7 (800) 511‑32‑27 Обсудить проект
Веб-разработка

Real-time приложения: архитектура и технологии

20 октября 2026·22 мин чтения
Юрий Пухов
Автор материалаЮрий ПуховCEO, YuSMP Group
Профиль автора
Добавить YuSMP как предпочитаемый источник в Google
Архитектура real-time приложения: потоки данных между серверами и устройствами в реальном времени

Коротко. Real-time приложение доставляет события пользователю за доли секунды без перезагрузки. Архитектура состоит из трёх слоёв: транспорт до клиента (WebSocket, SSE или long polling), шлюз соединений и брокер pub/sub (Redis, Kafka, NATS) между инстансами. Транспорт выбирают по направлению данных, брокер — по требуемым гарантиям доставки.

Протокол WebSocket стандартизован IETF ещё в декабре 2011 года в RFC 6455, а односторонний поток Server-Sent Events давно входит в HTML Living Standard и поддерживается всеми современными браузерами через стандартные Web API. Технологии зрелые, но архитектура real-time приложения по-прежнему остаётся местом, где проекты чаще всего спотыкаются на проде: соединения рвутся, события теряются, а сервер, который спокойно держал сотню тестовых пользователей, падает на первой рекламной кампании.

Бизнесу real-time нужен там, где задержка в несколько секунд стоит денег или доверия: чат с поддержкой, трекинг курьера или такси, биржевые котировки, совместное редактирование документов, дашборды склада и производства. Мы в YuSMP регулярно закладываем такие функции при разработке веб-приложений — от уведомлений в личном кабинете до полноценных чатов с историей и статусами прочтения.

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

Что такое real-time приложение и чем оно отличается от обычного

Real-time приложение — это приложение, в котором сервер сам отправляет клиенту новые данные в момент их появления, а не ждёт, пока клиент о них спросит. В классической модели «запрос-ответ» браузер или мобильное приложение инициирует каждый обмен: открыл страницу — получил данные, нажал «обновить» — получил снова. В real-time модели соединение остаётся открытым, и сервер толкает (push) события по мере их возникновения.

Важно разделять понятия. В промышленной автоматике и встроенных системах «реальное время» означает жёсткие гарантии: реакция за фиксированное время, иначе — авария (hard real-time). Веб и мобильные приложения относятся к мягкому реальному времени (soft real-time): допустимая задержка — обычно от 50 до 500 мс, а редкие опоздания неприятны, но не катастрофичны. Именно о таком real-time и пойдёт речь дальше.

Почему поллинг каждые N секунд не работает

Самый простой способ «оживить» интерфейс — опрашивать сервер по таймеру (short polling). Он хорош для прототипа, но плохо масштабируется. Посчитаем: 10 000 активных клиентов, каждый опрашивает сервер раз в 2 секунды, — это 5 000 запросов в секунду. Если новые данные появляются раз в минуту, подавляющее большинство этих запросов возвращает пустой ответ, но всё равно проходит авторизацию, логирование и обращение к базе.

Вторая проблема — задержка. При опросе раз в N секунд событие в среднем доходит до пользователя через N/2 секунд, а в худшем случае через N. Уменьшая интервал, вы снижаете задержку, но линейно увеличиваете нагрузку. Real-time транспорты разрывают эту зависимость: сервер отправляет данные ровно тогда, когда они есть, и только тем, кому они нужны.

Где бизнесу нужен real-time: типовые сценарии

Real-time нужен в продуктах, где ценность данных быстро падает со временем или где несколько людей работают с одним объектом одновременно. Требования к задержке и направление потока данных у сценариев разные — и это напрямую влияет на выбор технологий.

СценарийТипичное требование к задержкеНаправление данныхОсобенности
Чат, мессенджер, поддержкадо 200–500 мсдвустороннееистория, статусы «печатает» и «прочитано», presence
Уведомления в кабинете1–2 сот сервераважна доставка после оффлайна
Трекинг курьера, такси1–3 сот устройства к серверу и к клиентучастые координаты, мобильные сети
Котировки, торговля, аукционыдесятки–сотни мсв основном от серверавысокая частота, важен порядок событий
Дашборды, мониторинг1–5 сот сервераагрегаты, можно прореживать поток
Совместное редактированиедо 100–200 мсдвустороннееразрешение конфликтов (CRDT или OT)
Онлайн-игрыдесятки мсдвустороннеечасто нужен UDP-подобный транспорт
IoT-телеметриясекундыот устройствогромное число источников, MQTT на краю

Цифры в таблице — ориентиры из практики, а не стандарт: конкретный SLA задаёт бизнес. Например, для чата аналитики часто формулируют требование вида «p95 задержки доставки — не более 100 мс, p99 — не более 500 мс». Если вы планируете полноценный продукт-мессенджер, а не чат внутри сервиса, посмотрите наш разбор как создать свой мессенджер — там больше о продуктовой части.

Отдельно про совместное редактирование: когда два человека правят один документ одновременно, мало доставить изменения быстро — их нужно корректно объединить. Для этого применяют алгоритмы операционных преобразований (OT) или бесконфликтные реплицируемые типы данных (CRDT). Это отдельный слой поверх транспорта, и его сложность часто недооценивают.

Какие технологии передают данные в реальном времени

Транспорт real-time — это способ, которым события физически попадают от сервера к клиенту и обратно. В вебе выбор сводится к пяти вариантам: WebSocket, Server-Sent Events, long polling, WebTransport и push-уведомления, причём последние решают другую задачу. Разберём каждый.

WebSocket

WebSocket — это постоянный полнодуплексный канал поверх TCP: после установки соединения и клиент, и сервер могут отправлять сообщения в любой момент. Соединение начинается как обычный HTTP-запрос с заголовком Upgrade, после чего протокол «переключается» и дальше обмен идёт короткими фреймами — текстовыми или бинарными. Защищённая версия работает по схеме wss:// поверх TLS, как HTTPS.

GET /ws HTTP/1.1
Host: app.example.ru
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

Плюсы WebSocket — минимальные накладные расходы на сообщение, двусторонний обмен и поддержка бинарных данных. Минусы — нужно самостоятельно реализовать переподключение, heartbeat и догрузку пропущенного, а некоторые корпоративные прокси и старые балансировщики режут долгоживущие соединения. Подробная спецификация — в RFC 6455. Как подключить WebSocket на фронтенде, написать хук и переподключение, мы разобрали отдельно в статье WebSocket в React.

Server-Sent Events (SSE)

Server-Sent Events — это односторонний поток событий от сервера к клиенту поверх обычного HTTP-ответа, который не закрывается. В браузере его читает встроенный объект EventSource. У SSE есть две полезные вещи «из коробки»: автоматическое переподключение при обрыве и заголовок Last-Event-ID, по которому сервер понимает, с какого события продолжить поток.

Ограничения SSE — только текст (бинарные данные придётся кодировать) и только направление «сервер → клиент»: отправить данные на сервер клиент может обычным HTTP-запросом. Есть и неочевидный нюанс: при HTTP/1.1 браузеры держат около шести параллельных соединений на домен, и каждая вкладка с SSE занимает одно из них. С HTTP/2 эта проблема снимается, потому что все потоки мультиплексируются в одном соединении. Формат описан в стандарте WHATWG.

Long polling

Long polling — это эмуляция push поверх обычных запросов: клиент отправляет запрос, а сервер не отвечает, пока не появится событие или не истечёт таймаут (обычно 20–30 секунд). Получив ответ, клиент сразу отправляет следующий запрос. Задержка доставки при этом почти как у WebSocket, а работает схема абсолютно везде, где работает HTTP.

Цена универсальности — заголовки и авторизация в каждом цикле, лишние соединения и нагрузка на сервер при частых событиях. Поэтому long polling обычно используют как запасной транспорт: библиотеки вроде Socket.IO и SignalR автоматически откатываются на него, если WebSocket недоступен.

WebTransport и HTTP/3

WebTransport — новый браузерный API поверх HTTP/3 и QUIC. Он даёт несколько независимых потоков в одном соединении (потеря пакета в одном потоке не тормозит остальные) и ненадёжные датаграммы — аналог UDP, полезный для игр, видео и телеметрии, где свежие данные важнее доставки каждого пакета. Поддержка в браузерах пока неполная, а серверная инфраструктура только формируется, поэтому актуальный статус стоит проверять на MDN перед стартом проекта.

Параллельно развивается и сам WebSocket: RFC 8441 описывает, как запускать WebSocket внутри потока HTTP/2 вместо отдельного TCP-соединения. Для большинства бизнес-задач в 2026 году WebSocket и SSE остаются основным выбором, а WebTransport — технологией «на вырост» для специфических сценариев.

Push-уведомления (APNs и FCM)

Push-уведомления — это не транспорт для открытого приложения, а канал, чтобы «разбудить» пользователя, когда приложение закрыто или свёрнуто. Сообщение уходит через сервис платформы — Apple Push Notification service для iOS и Firebase Cloud Messaging для Android, — а не по вашему соединению. Доставка не гарантирована по времени, размер полезной нагрузки ограничен, поэтому push используют как сигнал «есть новое», а данные приложение забирает само после открытия.

Как выбрать: WebSocket, SSE или long polling — сравнительная таблица

Выбор транспорта определяется прежде всего направлением данных, затем — сетью, в которой живут пользователи, и требованиями к масштабу. Сравнение ниже собрано по нашей практике; цифры накладных расходов — ориентиры по замерам практиков, а не стандарт, и на вашей нагрузке они будут другими.

КритерийWebSocketSSELong pollingWebTransport
Направлениедвустороннеесервер → клиентсервер → клиент (эмуляция)двустороннее, несколько потоков
ПротоколTCP, Upgrade с HTTP/1.1 или поток HTTP/2HTTP/1.1 или HTTP/2HTTPHTTP/3, QUIC
Задержкаминимальнаяминимальнаянизкая, плюс цикл переподключенияминимальная
Накладные расходы трафикаоколо 5%около 10%200–400% при частых событияхнизкие
Прокси и корпоративные сетииногда режутсяобычно проходятпроходят вездеUDP часто блокируется
Автопереподключениеписать самомувстроенопо сути встроенописать самому
Бинарные данныеданет, только текстдада
Поддержка браузероввсе современныевсе современныелюбыенеполная
Сложность масштабированиясредняяниже среднейвысокая нагрузка на бэкендвысокая, мало готовых решений
Типичные сценариичаты, игры, совместная работауведомления, ленты, дашборды, стриминг ответов ИИзапасной транспорт, MVPигры, медиа, телеметрия

Короткие правила выбора, которыми мы пользуемся на старте проекта:

  • Данные идут только от сервера (уведомления, лента, статусы заказов, прогресс задачи) — берите SSE: он проще в эксплуатации и сам переподключается.
  • Нужен частый обмен в обе стороны (чат с индикатором набора, совместная доска, игра) — WebSocket.
  • Пользователи сидят в корпоративных сетях с жёсткими прокси — закладывайте long polling как автоматический фолбэк.
  • Нужны ненадёжные датаграммы и минимальная задержка — присмотритесь к WebTransport, но с запасным вариантом на WebSocket.
  • Приложение бывает закрыто — добавляйте push-уведомления поверх любого из транспортов.

На практике часто работает гибрид: SSE или WebSocket, пока пользователь в интерфейсе, push — когда он ушёл, и обычный REST для команд и загрузки истории. Не стоит заставлять один транспорт решать все задачи.

Из чего состоит архитектура real-time приложения

Архитектура real-time приложения — это цепочка компонентов, которая принимает событие в бизнес-логике и доставляет его всем нужным клиентам с заданной задержкой. Независимо от транспорта, путь события в зрелой системе выглядит примерно так:

  1. Клиент — браузер или мобильное приложение держит открытое соединение и подписывается на нужные каналы (комната чата, заказ, дашборд).
  2. Балансировщик или API Gateway — терминирует TLS, пробрасывает заголовки Upgrade, держит длинные таймауты и распределяет соединения по инстансам шлюза.
  3. Шлюз соединений — отдельный сервис, который хранит только открытые соединения и подписки и умеет быстро отправить сообщение нужным клиентам.
  4. Брокер pub/sub — шина, через которую бизнес-сервисы публикуют события, а инстансы шлюза получают те, на которые подписаны их клиенты.
  5. Бизнес-сервисы — обрабатывают команды, проверяют права, меняют состояние и публикуют события.
  6. Хранилища — основная база данных для истории и кэш (часто Redis) для быстрого состояния: кто онлайн (presence), последние события, курсоры клиентов.
Брокер сообщений pub/sub распределяет события между серверами real-time приложения

Такая схема хорошо ложится на сервисную архитектуру, но не требует её: на старте шлюз и бизнес-логика могут жить в одном монолите, если между ними уже есть граница через брокер. Если вы только выбираете между монолитом и сервисами, начните с нашего объяснения, что такое микросервисы простыми словами.

Шлюз соединений отдельно от бизнес-логики

Главное архитектурное решение — вынести долгоживущие соединения в отдельный слой. Причин три. Первая — деплой: бизнес-логику вы выкатываете несколько раз в день, и если соединения живут в том же процессе, каждый релиз рвёт их у всех пользователей. Вторая — профиль нагрузки: шлюзу нужна память на соединения и сеть, бизнес-сервисам — процессор и доступ к базе, масштабировать их выгоднее независимо. Третья — изоляция сбоев: зависший запрос к базе не должен блокировать отправку сообщений сотне тысяч клиентов.

Шлюз при этом остаётся «тупым»: он проверяет токен при подключении, хранит подписки и пересылает сообщения, но не принимает бизнес-решений. Готовые серверы вроде Centrifugo построены именно по этому принципу.

Модель событий и контракт

Контракт событий — это договорённость о формате сообщений между бэкендом, вебом и мобильными клиентами. Без него real-time быстро превращается в россыпь несовместимых JSON, которые ломаются при каждом релизе. Минимальный конверт события выглядит так:

{
  "type": "order.status_changed",
  "id": "01JB7Q2W8K3M5N",
  "ts": "2026-10-20T09:15:02.341Z",
  "version": 2,
  "channel": "order:48213",
  "data": { "status": "courier_assigned", "eta_min": 14 }
}

Поле id нужно для идемпотентности и догрузки, ts — для порядка и метрик задержки, version — для эволюции схемы без поломки старых мобильных клиентов, которые пользователи не обновляют месяцами. Каналы, типы событий и схемы удобно описывать в спецификации AsyncAPI — это аналог OpenAPI для событийных интерфейсов.

Pub/Sub и брокеры сообщений: Redis, Kafka, RabbitMQ, NATS

Pub/Sub (издатель-подписчик) — это шаблон обмена, в котором отправитель публикует событие в канал или топик, не зная, кто его получит, а брокер доставляет копию каждому подписчику. Шаблон подробно описан в центре архитектуры Microsoft Azure. В real-time системе брокер решает ключевую задачу: клиент подключён к одному инстансу шлюза, а событие возникло в сервисе, который ничего не знает об этом инстансе.

БрокерМодельГарантии доставкиХранение и повторКогда брать
Redis Pub/Subканалы, рассылка в памятиat-most-onceнет: оффлайн-подписчик сообщение теряетfan-out между инстансами шлюза, presence, «печатает…»
Redis Streamsжурнал с группами потребителейat-least-once с подтверждениямида, ограниченно по объёму памятидогрузка после реконнекта, небольшие очереди событий
Apache Kafkaраспределённый журнал, партицииat-least-once, есть транзакциида, долговременно, перечитывание по offsetбольшой поток событий, аналитика, event sourcing
RabbitMQочереди и обменники с маршрутизациейat-least-once с подтверждениямипока сообщение не обработанозадачи и команды со сложной маршрутизацией
NATS / JetStreamлёгкие subject-ы, JetStream — с хранениемCore — at-most-once, JetStream — at-least-onceв JetStream — данизкая задержка, много каналов, простая эксплуатация

Чаще всего путаница возникает вокруг Redis. Классический Redis Pub/Sub работает по модели at-most-once: если подписчик в момент публикации не подключён, сообщение для него просто исчезает. Для мгновенного fan-out между инстансами шлюза это нормально, а для событий, которые нельзя потерять, — нет. Там нужны Redis Streams, JetStream или Kafka.

Apache Kafka хранит события в журнале, и любой потребитель может перечитать их с нужного места. Это мощно, но Kafka не предназначена для миллионов мелких динамических каналов вроде «комната чата №48213» и требует серьёзной эксплуатации. Типичная зрелая схема — Kafka как шина бизнес-событий между сервисами и Redis или NATS для быстрой раздачи клиентам через шлюз.

Как масштабировать real-time: от 1 000 до 1 000 000 соединений

Масштабирование real-time — это рост числа одновременных соединений и событий без роста задержки. До нескольких тысяч соединений справляется один сервер почти без усилий. Дальше начинаются архитектурные решения:

  • Горизонтальное масштабирование шлюза. Несколько одинаковых инстансов за балансировщиком; каждый держит свою часть соединений и подписывается в брокере только на каналы своих клиентов.
  • Общий брокер вместо sticky sessions. Привязка клиента к конкретному серверу (sticky sessions) нужна для long polling и некоторых библиотек, но не решает доставку между инстансами. Событие должно уходить через брокер на все инстансы, где есть подписчики канала.
  • Шардирование каналов. При сотнях тысяч комнат одна шина становится узким местом — каналы распределяют по шардам брокера по хешу идентификатора.
  • Лимиты операционной системы. Каждое соединение — это файловый дескриптор и память под буферы. Лимиты дескрипторов, диапазон портов балансировщика и параметры TCP-стека настраивают заранее, а не после первого падения.
  • Backpressure и медленные клиенты. Клиент на плохом мобильном интернете не успевает принимать сообщения, и буфер на сервере растёт. Нужен лимит исходящего буфера на соединение: при переполнении — прореживать некритичные события или отключать клиента с просьбой переподключиться.
  • Graceful-деплой. При выкатке новой версии шлюза инстансы выводят из балансировки постепенно и закрывают соединения порциями, а не все сразу.
  • Защита от шторма переподключений. Если сто тысяч клиентов отвалились одновременно, они не должны так же одновременно вернуться. Переподключение — с экспоненциальной задержкой и случайным джиттером, а на сервере — лимит скорости новых подключений.

Отдельная статья расходов — fan-out. Сообщение в канал с десятью подписчиками дёшево, а одно событие для ста тысяч подписчиков (например, изменение котировки) означает сто тысяч отправок. Такие «широкие» каналы проектируют отдельно: прореживают частоту, агрегируют обновления и раздают их пачками.

Надёжность: гарантии доставки, порядок и переподключение

Надёжность real-time системы определяется тем, что происходит с событием при сбоях: обрыве сети, перезапуске сервера, уходе клиента в оффлайн. Есть три уровня гарантий доставки:

  • At-most-once — событие доставляется не более одного раза и может потеряться. Подходит для индикатора «печатает…», позиции курсора, промежуточных котировок.
  • At-least-once — событие доставляется точно, но иногда дважды. Это основной рабочий режим для сообщений чата, статусов заказов, уведомлений.
  • Effectively-once — at-least-once плюс идемпотентная обработка на клиенте. Настоящая «ровно один раз» доставка по сети в общем случае недостижима, поэтому её эмулируют дедупликацией по id события.

Порядок. Глобальный порядок всех событий системы дорог и почти никогда не нужен. Достаточно гарантировать порядок в рамках канала: все события одного чата или одного заказа идут через одну партицию или шард и нумеруются последовательно. Клиент, получив событие с номером 15 после номера 13, понимает, что пропустил 14, и запрашивает его.

Догрузка после реконнекта. При переподключении клиент передаёт последний полученный идентификатор: в SSE это делает сам браузер через Last-Event-ID, в WebSocket — ваш протокол, в Kafka — offset потребителя. Сервер досылает пропущенное из журнала или из базы. Без этого механизма каждый обрыв сети — это потерянные сообщения, и пользователи обнаруживают их только при перезагрузке страницы.

Heartbeat. TCP-соединение может «умереть» молча — например, при смене сети у мобильного клиента. Поэтому стороны регулярно обмениваются ping-pong сообщениями (в WebSocket для этого есть служебные фреймы). Нет ответа за несколько интервалов — соединение считается мёртвым, сервер освобождает ресурсы, клиент переподключается.

Оффлайн-очередь на клиенте. Сообщения, которые пользователь отправил без сети, складываются в локальную очередь и уходят после восстановления связи — с теми же идентификаторами, чтобы сервер не создал дубли.

Real-time в мобильных приложениях: что учесть

Real-time в мобильном приложении отличается от веба тем, что операционная система, а не разработчик, решает, когда приложению можно держать соединение. iOS и Android агрессивно ограничивают фоновую работу ради батареи: через короткое время после сворачивания сокеты закрываются, а фоновые задачи откладываются.

Поэтому рабочая схема почти всегда гибридная: WebSocket или SSE, пока приложение на экране, и push-уведомления через APNs и FCM, когда оно в фоне или закрыто. При возврате в приложение клиент переподключается и синхронизирует состояние — догружает пропущенные события по курсору, а не перезапрашивает всё целиком.

Что ещё важно закладывать в архитектуру мобильного клиента:

  • Смена сети. Переход с Wi-Fi на LTE меняет IP-адрес и рвёт TCP-соединение. Клиент должен быстро заметить это и переподключиться, не дожидаясь таймаута heartbeat.
  • Батарея. Слишком частый heartbeat держит радиомодуль активным и заметно расходует заряд. Интервал подбирают как компромисс между скоростью обнаружения обрыва и энергопотреблением.
  • Нестабильный канал. В метро и лифте связь пропадает на секунды — интерфейс должен показывать статус «соединение…», а не ошибку, и хранить неотправленное в оффлайн-очереди.
  • Старые версии. Мобильные клиенты обновляются медленно, поэтому версионирование контракта событий здесь критично.

Если real-time функции нужны и в вебе, и в приложениях под iOS и Android, протокол событий и логику синхронизации лучше проектировать сразу для всех платформ. Мы делаем это в рамках проектов по разработке мобильных приложений — один контракт событий для веба и мобильных клиентов экономит месяцы на поддержке.

Безопасность real-time соединений

Безопасность real-time соединений строится на тех же принципах, что и для REST, но с поправкой на то, что соединение живёт долго, а проверка «на входе» происходит один раз. Базовый набор мер:

  • Только шифрованные соединения. wss:// и HTTPS для SSE — без исключений, включая внутренние стенды, доступные снаружи.
  • Аутентификация при подключении. Короткоживущий токен проверяется при handshake. Браузерный WebSocket не позволяет передать произвольные заголовки, поэтому токен часто кладут в query-строку — тогда это должен быть одноразовый тикет на несколько секунд, иначе он осядет в логах прокси.
  • Проверка Origin. Сервер отклоняет подключения с чужих доменов — это защита от межсайтового перехвата WebSocket.
  • Авторизация на каждый канал. Подключиться — не значит получить доступ ко всем комнатам. Подписка на канал проверяется отдельно, а при отзыве прав соединение должно отписываться или разрываться.
  • Истечение токена. Соединение может жить дольше токена; нужен механизм обновления токена без переподключения или принудительный разрыв по истечении.
  • Лимиты. Ограничения на число соединений с одного пользователя и IP, на частоту и размер сообщений, на число подписок. Без них один клиент может занять ресурсы, рассчитанные на тысячи.
  • Валидация входящих сообщений. Всё, что приходит от клиента по сокету, проверяется так же строго, как тело HTTP-запроса.

Готовые платформы или своя инфраструктура

Готовая real-time платформа — это облачный сервис, который берёт на себя соединения, масштабирование и доставку, а вы публикуете события через API. К этому классу относятся Firebase, Supabase Realtime, Azure Web PubSub, Ably и Pusher. Альтернатива — своя инфраструктура на открытых решениях: Socket.IO для Node.js, SignalR для .NET, Centrifugo как отдельный сервер плюс брокер.

КритерийManaged-платформаСвоя инфраструктура
Скорость стартадни: SDK и готовая консольнедели: шлюз, брокер, мониторинг
Стоимость на малом объёменизкая, часто бесплатный тариффиксированные затраты на серверы и DevOps
Стоимость на большом объёмерастёт с соединениями и сообщениямирастёт медленнее, предсказуема
Контроль данных и 152-ФЗданные у провайдера, часто за рубежомполный контроль, хранение в РФ
Доступность из Россиичасть сервисов ограничена или рискованназависит только от вас
Vendor lock-inвысокий: свой SDK и модель данныхнизкий, стандартные протоколы
Гибкость логикив рамках возможностей платформылюбая

Для российского бизнеса отдельный аргумент — закон 152-ФЗ: персональные данные граждан РФ должны записываться и храниться в базах на территории России, а переписка в чате почти всегда содержит персональные данные. Плюс ряд зарубежных сервисов ограничил работу с российскими компаниями. Поэтому managed-платформы мы чаще рекомендуем для прототипов и внутренних инструментов без персональных данных, а продакшн — на собственной инфраструктуре или у российского облачного провайдера.

Как выглядит real-time на конкретном BaaS-решении, включая структуру данных и правила безопасности, разобрано в статье Firebase Realtime Database: чат, код, архитектура.

Как спроектировать real-time систему: 7 шагов

Проектирование real-time системы — это последовательность решений от бизнес-требований к инфраструктуре. Мы проходим эти шаги на этапе аналитики, до написания кода:

  1. Зафиксируйте сценарии и SLA. Какие события, кому и с какой задержкой доставлять (p95 и p99), сколько пользователей онлайн в пике и сколько событий в секунду. Без этих цифр невозможно ни выбрать технологии, ни проверить результат.
  2. Выберите транспорт по направлению данных. SSE — для потока от сервера, WebSocket — для двустороннего обмена, long polling — как фолбэк, push — для фона и оффлайна.
  3. Опишите контракт событий. Конверт с type, id, ts и version, список каналов и правила доступа к ним. Удобный формат — AsyncAPI.
  4. Выберите брокер по гарантиям доставки. Можно ли потерять событие? Нужно ли перечитывать историю? От ответов зависит выбор между Redis Pub/Sub, Redis Streams, NATS JetStream и Kafka.
  5. Спроектируйте шлюз и масштабирование. Отдельный слой соединений, балансировка, fan-out через брокер, лимиты ОС и буферов, порядок деплоя без массовых обрывов.
  6. Заложите надёжность и мониторинг. Heartbeat, переподключение с экспоненциальной задержкой и джиттером, догрузка по курсору, оффлайн-очередь, метрики и алерты.
  7. Проведите нагрузочный тест соединений. Целевое число одновременных подключений, массовое переподключение, медленные клиенты, отказ одного инстанса — всё это проверяется до релиза.

Мониторинг real-time: какие метрики смотреть

Мониторинг real-time системы отличается от мониторинга REST API тем, что главная единица — не запрос, а соединение и событие. Стандартные графики RPS и времени ответа здесь почти ничего не показывают. Минимальный набор метрик:

  • Активные соединения — всего и по инстансам; резкое падение означает массовый обрыв, перекос — проблему балансировки.
  • Скорость подключений и отключений — всплеск переподключений говорит о сетевой проблеме или сбое шлюза раньше, чем пожалуются пользователи.
  • End-to-end задержка доставки — от публикации события до получения клиентом, в перцентилях p50, p95, p99. Именно её сравнивают с SLA.
  • Лаг брокера (consumer lag) — насколько потребители отстают от публикации; растущий лаг — признак того, что система не успевает.
  • Размер исходящих буферов — растущие буферы означают медленных клиентов или перегрузку сети.
  • Ошибки аутентификации и отклонённые подписки — индикатор и багов в клиенте, и попыток злоупотребления.

Типовой стек — Prometheus для сбора метрик и Grafana для дашбордов и алертов. Обязательные алерты: падение числа соединений больше чем на заданный процент за минуту, рост p99 задержки выше SLA, шторм переподключений и рост consumer lag.

Типичные ошибки при разработке real-time функций

Большинство проблем real-time на проде повторяются от проекта к проекту. Вот ошибки, которые мы чаще всего видим на аудитах:

  • WebSocket там, где хватит SSE. Двусторонний канал для уведомлений «сервер → клиент» добавляет работы по переподключению и проксированию без какой-либо пользы.
  • Бизнес-логика в шлюзе. Каждый релиз рвёт все соединения, а тяжёлый запрос к базе тормозит доставку всем клиентам инстанса.
  • Нет догрузки после обрыва. Сообщения, пришедшие за время переподключения, теряются молча.
  • Redis Pub/Sub для событий, которые нельзя терять. Модель at-most-once не подходит для платежей, заказов и сообщений чата без отдельного хранения.
  • Нет лимитов. Ни на число соединений, ни на размер и частоту сообщений — до первого клиента с ошибкой в цикле отправки.
  • Забытые таймауты прокси. В nginx параметр proxy_read_timeout по умолчанию равен 60 секундам: соединение без трафика дольше минуты будет разорвано. Нужны heartbeat чаще этого интервала или увеличенный таймаут.
  • Тестирование на десяти пользователях. Проблемы real-time проявляются на тысячах соединений и при массовом переподключении — без нагрузочного теста вы узнаете о них от пользователей.

Пример минимальной настройки nginx для проксирования WebSocket:

location /ws/ {
    proxy_pass http://ws_gateway;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 120s;
}

Заключение

Хорошая архитектура real-time приложения строится не вокруг модного протокола, а вокруг требований: какие события, кому, с какой задержкой и что делать, если событие не дошло. Транспорт выбирают по направлению данных, брокер — по гарантиям доставки, а надёжность обеспечивают переподключение, догрузка по курсору и мониторинг задержки. Если заложить это на этапе проектирования, real-time функции масштабируются вместе с продуктом, а не становятся источником ночных инцидентов.

Найдем лучшее решение для вас

* При условии заключения договора на разработку.

Частые вопросы (FAQ)

Что такое real-time приложение простыми словами?

Real-time приложение — это приложение, в котором сервер сам присылает пользователю новые данные сразу, как только они появились, без перезагрузки страницы и без постоянных запросов «есть ли что-то новое». Так работают мессенджеры, трекинг курьера на карте, биржевые котировки и онлайн-доски для совместной работы. Обычно задержка доставки составляет доли секунды.

Чем WebSocket отличается от SSE?

WebSocket — двусторонний канал: и клиент, и сервер могут отправлять сообщения в любой момент, поддерживаются текст и бинарные данные. SSE (Server-Sent Events) — односторонний поток от сервера к клиенту поверх обычного HTTP, только текст, зато со встроенным автопереподключением и догрузкой по Last-Event-ID. Если данные идут только от сервера, SSE проще и дешевле в поддержке.

Когда достаточно long polling?

Long polling подходит, когда событий немного, пользователей сотни или единицы тысяч, а приложение должно работать в любых сетях, включая корпоративные прокси, которые режут WebSocket. Это хороший запасной транспорт и быстрый способ запустить MVP. При частых событиях и большом числе клиентов long polling становится дорогим по трафику и нагрузке на сервер.

Сколько соединений выдерживает один сервер WebSocket?

Точной цифры нет: всё зависит от памяти на соединение, частоты сообщений, логики обработки и настроек операционной системы. При лёгких соединениях без тяжёлой логики один инстанс шлюза держит десятки, а иногда и сотни тысяч подключений. Это ориентир, а не гарантия: реальный потолок для вашей системы показывает только нагрузочный тест.

Нужен ли Kafka для чата?

Для MVP и большинства чатов Kafka не нужна: доставку между инстансами шлюза закрывают Redis или NATS, а историю сообщений хранят в базе данных. Kafka оправдана, когда нужен долговременный журнал событий, перечитывание с любого места, аналитика в потоке и очень большой объём сообщений. Начинать с Kafka без такой потребности — лишняя сложность в эксплуатации.

Как real-time работает в мобильном приложении в фоне?

iOS и Android закрывают сетевые соединения приложений, ушедших в фон, чтобы беречь батарею. Поэтому WebSocket держат только пока приложение открыто, а в фоне пользователя будят push-уведомлениями через APNs и FCM. После возврата в приложение клиент переподключается и догружает пропущенные события по последнему известному идентификатору или курсору.

Сколько стоит добавить real-time в существующее приложение?

Стоимость зависит от сценариев, числа пользователей, требований к гарантиям доставки и того, насколько готов текущий бэкенд к событийной модели. Добавить уведомления через SSE — одна задача, а построить чат с историей, статусами прочтения и мобильными push — совсем другая. Корректная оценка возможна после технического аудита и описания сценариев.

Нужны real-time функции в вашем продукте?

Спроектируем и разработаем веб-приложение с чатами, уведомлениями и live-обновлениями — от выбора протокола до нагрузочного теста.

Обсудить разработку веб-приложения