Фраза:
Хотим, чтобы всё работало в реальном времени.
встречается в технических заданиях очень часто.
Например заказчик хочет, чтобы:
- новые сообщения появлялись без обновления страницы;
- статус заказа менялся сразу;
- администратор моментально видел новую заявку;
- платёж автоматически переходил в состояние «Оплачен»;
- данные CRM синхронизировались без ручного обновления;
- прогресс длительной операции отображался пользователю;
- уведомления появлялись сразу после события.
На первый взгляд все эти задачи похожи.
Кажется, достаточно выбрать одну «real-time технологию» и использовать её везде.
Например:
WebSocketпотому что он звучит наиболее современно.
На практике это почти всегда неправильный подход.
У разных задач совершенно разная природа.
Для одной:
polling каждые 30 секундбудет проще, дешевле и надёжнее.
Для другой действительно нужен:
WebSocket.Для третьей WebSocket вообще не решает основную задачу, потому что событие приходит не от браузера пользователя, а от внешней системы.
Тогда нужен:
webhook.Поэтому правильный вопрос звучит не:
Что лучше — polling, webhook или WebSocket?
А:
Кто кому должен сообщить об изменении, насколько быстро это должно произойти и насколько критично пропустить событие?
Разберём эти три подхода без маркетинговой магии вокруг слов «real time».
Сначала определим участников
В обычном веб-продукте могут участвовать:
Пользовательский браузер
│
▼
Наш backend
│
▼
Наша база данныхНо могут появляться и внешние сервисы:
Платёжная система
CRM
Служба доставки
Email provider
Банк
Сторонний APIТеперь направление обмена информацией может быть разным.
Например:
Browser
→ Backendили:
Backend
→ Browserили:
External service
→ Backend.Именно направление события часто определяет технологию.
Самое простое правило
Можно начать с такой схемы:
Клиент периодически спрашивает сервер:
«Есть что-нибудь новое?»
→ polling
Внешний сервис сам сообщает нашему backend:
«У меня произошло событие»
→ webhook
Наш backend должен сразу отправлять события
подключённому браузеру:
«Вот изменение»
→ WebSocketУже этого достаточно, чтобы не пытаться решить все три задачи одной технологией.
Что такое polling
Polling — это самый простой вариант.
Клиент периодически делает запрос:
GET /api/orders/1842/statusи получает:
{
"status": "processing"
}Через несколько секунд снова:
GET /api/orders/1842/statusТеперь:
{
"status": "completed"
}То есть никто специально не отправлял клиенту событие.
Клиент сам регулярно спрашивал:
Что-нибудь изменилось?
Это похоже на проверку почтового ящика
Каждые пять минут человек подходит:
Есть письмо?
Нет.
Есть письмо?
Нет.
Есть письмо?
Да.Это и есть polling.
Почему polling часто считают плохим решением
Потому что он делает лишние запросы.
Например:
1000 пользователейпроверяют статус каждые:
5 секунд.Получаем:
12 запросов в минуту
×
1000
=
12 000 запросов в минуту.При этом большинство ответов могут быть:
ничего нового.Кажется неэффективным.
И действительно, для некоторых продуктов это плохая архитектура.
Но не для всех.
Polling имеет огромное преимущество — простоту
Не нужны:
постоянные соединения;
WebSocket gateway;
reconnect logic;
connection registry;
heartbeat;
message fan-out.Обычный HTTP.
Обычная авторизация.
Обычные backend endpoints.
Обычный reverse proxy.
Поэтому polling отлично подходит, если задержка допустима
Например пользователь отправил документ на генерацию.
Процесс занимает:
2–5 минут.Frontend показывает:
Файл формируется...и проверяет:
GET /api/jobs/123раз в:
5 секунд.Нужен ли здесь WebSocket?
Чаще всего нет.
Разница между:
результат появился в 12:00:01и:
пользователь увидел его в 12:00:05никакого бизнес-значения не имеет.
Ещё пример — статус заказа
Заказ:
Принят
↓
Комплектуется
↓
Передан в доставку
↓
ДоставленЕсли изменение происходит раз в несколько часов, WebSocket ради доставки статуса на три секунды быстрее будет архитектурным излишеством.
Polling раз в:
30–60 секундможет быть более чем достаточным.
Polling особенно хорош для административных интерфейсов
Например dashboard показывает:
новые заявки;
очередь задач;
статус backup;
метрики;
состояние интеграций.Если информация обновляется раз в:
15–30 секунд,пользователь всё равно воспринимает интерфейс как практически живой.
Real time не всегда означает миллисекунды
Для разных задач «быстро» означает разное.
Например:
Чат:
100–500 мс желательно.
Новая заявка админу:
1–5 секунд отлично.
Изменение статуса заказа:
10–30 секунд нормально.
Построение отчёта:
несколько секунд задержки неважно.
Обновление статистики:
30–60 секунд может быть достаточно.Поэтому требование:
Нужно real time.
нужно переводить в конкретное:
Какую максимальную задержку пользователь готов заметить?
Polling бывает адаптивным
Не обязательно спрашивать сервер каждые две секунды вечно.
Например:
первые 30 секунд:
каждые 2 секунды
потом:
каждые 5 секунд
через минуту:
каждые 15 секундЭто снижает нагрузку.
Можно останавливать polling
Например job перешёл:
RUNNING
→ COMPLETED.После этого:
polling stop.Можно прекращать polling, если вкладка неактивна
Browser Page Visibility API позволяет понимать:
пользователь вообще смотрит страницу?Если нет:
interval ↑или запросы временно останавливаются.
Таким образом polling не обязательно примитивен
Он может быть:
адаптивным;
экономным;
условным;
зависящим от состояния.Когда polling становится плохим
Например чат.
Пользователь пишет:
Привет.
Второй пользователь должен увидеть сообщение практически сразу.
Если polling раз в:
30 секунд,чат ощущается сломанным.
Если раз в:
1 секунду,на:
10 000 пользователейсоздаётся огромный поток одинаковых HTTP-запросов.
Вот здесь появляется смысл WebSocket.
Что такое WebSocket
Обычный HTTP работает примерно так:
Client
→ Request
→ Server
Server
→ Response
Connection endsДля следующего обновления нужен новый request.
WebSocket строит другое взаимодействие.
Клиент устанавливает соединение:
Browser
⇄
Serverи сохраняет его.
Теперь обе стороны могут отправлять данные в любой момент.
Например чат
Пользователь A пишет:
ПриветBackend сохраняет сообщение.
И сразу отправляет через WebSocket:
new_messageпользователю B.
Не нужно ждать следующего:
GET /messages.Поэтому WebSocket подходит для настоящего интерактивного real time
Например:
чат;
онлайн-игра;
совместное редактирование;
торговый терминал;
живой мониторинг;
presence;
оперативные уведомления;
диспетчерские панели.Но WebSocket — это не просто «HTTP быстрее»
С ним появляется новый класс инфраструктуры.
Система должна понимать:
кто сейчас подключён;
какому пользователю принадлежит connection;
к какому проекту он имеет доступ;
что делать после reconnect;
как обнаружить мёртвое соединение;
как масштабировать несколько серверов.Представим один backend
User A
│
▼
Server 1и:
User B
│
▼
Server 1Server 1 легко знает оба connection.
Теперь backend масштабировали
User A
│
▼
Server 1
User B
│
▼
Server 2Пользователь A отправляет сообщение на:
Server 1.Но connection пользователя B находится:
на Server 2.Как Server 1 доставит ему событие?
Теперь нужен межсерверный слой
Например:
Redis Pub/Sub;
Redis Streams;
NATS;
RabbitMQ;
другой message broker.Схема:
User A
↓
Server 1
↓
Pub/Sub
↓
Server 2
↓
User BТо есть простое требование:
Сделайте всё в реальном времени.
может заметно изменить backend architecture.
WebSocket требует reconnect
Мобильный интернет пропал.
Wi-Fi сменился.
Ноутбук проснулся после сна.
Nginx перезапущен.
Deploy заменил container.
WebSocket разорван.
Клиент должен:
обнаружить disconnect;
подождать;
переподключиться;
повторно авторизоваться;
восстановить подписки.А что произошло, пока соединения не было?
Очень важный вопрос.
Например:
12:00 connection lost
12:01 новое сообщение
12:02 новое сообщение
12:03 reconnectЕсли система просто снова открыла socket, пользователь может навсегда потерять два события.
Поэтому WebSocket не отменяет обычный API
Хорошая архитектура часто выглядит так:
REST/HTTP
=
получить текущее состояние
WebSocket
=
сообщить, что состояние изменилосьПосле reconnect клиент может сделать
GET /api/messages?after=lastKnownIdи восстановить пропущенные данные.
Это очень важный принцип
WebSocket — канал доставки событий, а не обязательно источник истины.
Источник истины остаётся:
database/API.WebSocket особенно легко переоценить
Например заказчик говорит:
Хочу, чтобы статус оплаты менялся моментально. Значит нужен WebSocket.
Но откуда наш backend вообще узнает, что платёж прошёл?
WebSocket между:
Browser
⇄
Наш backendэтого не решает.
Платёж происходит в:
внешней платёжной системе.Именно здесь нужен webhook.
Что такое webhook
Webhook — это ситуация, когда один сервер сообщает другому серверу о событии.
Например:
Платёжная система
↓
POST /webhooks/payment
↓
Наш backendPayload:
{
"type": "payment.succeeded",
"paymentId": "pay_123"
}Теперь backend знает:
Платёж состоялся.
Webhook — не технология обновления браузера
Это очень важное различие.
Webhook работает:
Server
→
Server.WebSocket чаще используется:
Server
⇄
Client.Поэтому одна реальная функция может использовать сразу обе технологии
Например пользователь оплачивает заказ.
Полный путь:
Пользователь
↓
Платёжная система
↓
платёж выполнен
↓
Webhook
↓
Наш backend
↓
Payment = PAID
↓
WebSocket
↓
Browser
↓
«Оплата получена»Вот здесь:
webhookи:
WebSocketне конкуренты.
Они решают разные части одной задачи.
Можно заменить WebSocket polling'ом
Тот же процесс:
Платёж
↓
Webhook
↓
Backend
↓
Payment = PAIDа frontend каждые три секунды:
GET /api/payment/statusЧерез несколько секунд видит:
PAID.Какая архитектура лучше?
Зависит от продукта.
Если после оплаты пользователь может подождать:
2–3 секунды,polling проще.
Если интерфейс должен реагировать практически мгновенно:
WebSocketможет быть оправдан.
Webhook при этом нужен в обоих случаях.
Это одна из главных ошибок в требованиях
Заказчик говорит:
Нам нужен WebSocket для интеграции с CRM.
Но если CRM должна сама сообщать:
Лид изменился,
правильный механизм, возможно:
CRM webhook
→ наш backend.WebSocket здесь вообще не участвует.
Или наоборот
CRM не поддерживает webhook.
Есть только:
GET /crm/leadsТогда никакой WebSocket на нашей стороне не заставит CRM внезапно отправлять события.
Придётся использовать polling внешнего API.
Получается интересная комбинация
CRM
↑
polling
│
наш backend
↓
WebSocket
│
BrowserBackend каждые:
30 секундпроверяет CRM.
Когда находит изменение, моментально отправляет его открытой админ-панели через WebSocket.
Для пользователя интерфейс выглядит:
real time.Хотя источник данных обновляется polling'ом.
Это важный вывод
Real-time UX и real-time source — не одно и то же.
Интерфейс может выглядеть мгновенным, даже если одна часть системы обновляется с небольшой задержкой.
Что значит «всё в реальном времени» для бизнеса
Лучше разбить требование на события.
Например:
| Событие | Допустимая задержка |
|---|---|
| Сообщение в чате | < 1 сек |
| Новая заявка админу | 1–5 сек |
| Статус оплаты | 1–5 сек |
| Статус доставки | 30–60 сек |
| Обновление dashboard | 15–30 сек |
| Финансовый отчёт | минуты |
После этого выбор технологии часто становится очевиден.
Пример: чат
Требования:
сообщения сразу;
typing indicator;
online status.Хороший кандидат:
WebSocket.Почему?
Событий много.
Задержка заметна.
Связь двухсторонняя.
Можно ли использовать webhook?
Нет в основной части.
Оба пользователя находятся внутри нашего продукта.
Нет внешнего сервера, которому нужно уведомить наш backend.
Можно ли polling?
Технически:
да.Но UX при масштабе и высокой частоте будет хуже.
Пример: платёж
Требование:
Как только банк подтвердил платёж, заказ должен стать оплаченным.
Главный механизм:
payment provider
→ webhook
→ backend.Нельзя полагаться только на browser redirect
Например после оплаты provider отправляет пользователя:
/success.Это ещё не надёжное подтверждение оплаты.
Пользователь может:
закрыть вкладку;
потерять интернет;
подделать URL.Backend должен получить доверенное состояние через:
webhookили дополнительный API reconciliation.
А как обновить экран пользователя?
Можно:
pollingили:
WebSocket.Это отдельное решение.
Пример: новая заявка админу
Пользователь отправил форму.
Backend уже знает о новой заявке.
Нужно показать админу:
Новая заявка #1842.Варианты:
Polling
Админ-панель каждые:
10 секундпроверяет новые заявки.
Для небольшого проекта этого вполне достаточно.
WebSocket
Backend сразу:
push new_leadв открытый dashboard.
Если скорость действительно важна — хороший вариант.
Webhook здесь не нужен
Потому что событие уже возникло внутри нашего backend.
Пример: синхронизация со службой доставки
Нужно знать статус:
Принято
В пути
ДоставленоЕсли служба доставки предоставляет webhook:
используем webhook.Если не предоставляет:
polling API.WebSocket внутри нашего сайта не решает получение внешнего статуса.
Пример: прогресс генерации отчёта
Пользователь нажал:
Сформировать PDF.Backend создаёт background job.
Процесс:
0%
↓
30%
↓
70%
↓
100%.Нужен ли WebSocket?
Если отчёт строится:
20 секунди хочется красивый живой progress:
WebSocketили Server-Sent Events могут быть хорошим решением.
Но если задача обычно занимает
3 секунды,проще показать spinner.
Если процесс занимает пять минут
Polling каждые:
5 секундможет быть проще и абсолютно достаточен.
Не каждое percentage update имеет реальную ценность
Иногда система показывает:
43%
44%
45%но backend на самом деле не знает точный progress.
Разработчик просто придумал визуальную анимацию.
Тогда WebSocket никак не делает систему честнее.
Polling: преимущества
простая реализация;
обычный HTTP;
простая авторизация;
легко кешировать;
легко логировать;
хорошо работает через proxies;
простое горизонтальное масштабирование;
простой recovery после offline.Polling: недостатки
лишние запросы;
задержка зависит от interval;
при слишком частом polling растёт нагрузка;
неидеален для очень частых событий.Webhook: преимущества
внешняя система сообщает сама;
нет постоянного опроса;
событие может прийти быстро;
хорош для server-to-server интеграций.Webhook: недостатки
публичный endpoint;
нужна проверка подписи;
дубли;
retry;
replay protection;
out-of-order события;
нужно durable processing.Webhook — не просто:
POST + JSON.Это отдельный интеграционный протокол.
WebSocket: преимущества
низкая задержка;
двусторонняя связь;
удобен для частых событий;
сильный real-time UX.WebSocket: недостатки
постоянные соединения;
reconnect;
heartbeat;
масштабирование;
connection state;
пропущенные события;
fan-out между серверами;
более сложное тестирование.А что такое Server-Sent Events?
Есть ещё промежуточный вариант:
SSEили Server-Sent Events.
Он часто остаётся за рамками разговора:
Polling или WebSocket?
Хотя для некоторых задач подходит отлично.
SSE работает только в направлении
Server
→
Browser.Клиент открывает HTTP connection.
Server постепенно отправляет события.
Например
progress;
notifications;
logs;
status updates.Если браузеру не нужно отправлять множество сообщений обратно по тому же каналу, SSE может быть проще WebSocket.
Чат
Нужна двусторонняя активная связь:
WebSocket.Живой progress build
Нужно только:
Server → Browser.Можно рассмотреть:
SSE.Но даже SSE не нужно выбирать автоматически
Если update раз в:
30 секунд,polling всё равно может быть проще.
Поэтому реальный выбор чаще выглядит так
Polling
Webhook
SSE
WebSocketа не только:
WebSocket = современно.Почему «давайте WebSocket везде» обычно плохая идея
Потому что WebSocket решает одну конкретную проблему:
частая низколатентная связь между уже подключёнными сторонами.
Он не решает автоматически:
надёжную бизнес-доставку;
долговременное хранение событий;
восстановление истории;
синхронизацию с внешним provider;
точность состояния после disconnect.Представим уведомления
Backend отправил:
new_notificationчерез WebSocket.
В этот момент пользователь был offline.
Уведомление потеряно?
Если да — архитектура ненадёжна.
Значит само уведомление должно храниться
Например:
notifications tableсодержит:
id
user_id
message
created_at
read_atWebSocket только сообщает:
Появилась новая запись.
После reconnect frontend делает
GET /api/notifications?after=...и получает пропущенные.
То есть правильная модель
Database
=
истина
WebSocket
=
ускоритель доставкиЭто очень важный принцип для заказчика
Когда звучит:
Мне нужно, чтобы уведомления не терялись.
ответ:
«Нужен WebSocket»недостаточен.
Нужна:
durable notification storage.То же относится к чату
Сообщение должно сначала стать:
durable data.Например:
INSERT messages
COMMITа потом:
WebSocket broadcast.Не наоборот
Плохо:
WebSocket send
↓
DB insert
↓
database error.Получатель увидел сообщение, которого официально не существует.
Хорошая схема
Sender
↓
POST /messages
↓
DB transaction
↓
COMMIT
↓
WebSocket event
↓
RecipientsЕсли broadcast потерялся, сообщение всё равно можно восстановить через API.
WebSocket и background jobs
Представим worker выполняет:
импорт 100 000 строк.Frontend хочет progress.
Worker не должен напрямую знать WebSocket connection пользователя.
Лучше
Worker
↓
updates job progress
↓
event bus
↓
WebSocket layer
↓
Browserили frontend периодически получает progress через polling.
Это сохраняет архитектурные границы
Worker занимается:
работой.Realtime gateway:
доставкой UI events.Что делать после reconnect WebSocket
Никогда не предполагать:
Если socket снова открылся, состояние актуально.
Лучше иметь:
lastEventIdили:
lastMessageIdи после восстановления сделать:
sync.До разрыва клиент видел:
message_id = 1830.После reconnect:
GET /messages?after=1830Backend возвращает:
1831
1832
1833.Теперь client догнал состояние.
Для некоторых систем события можно replay
Например server хранит короткий event stream.
Клиент сообщает:
last sequence = 945.Server продолжает:
946...Но это уже более сложная архитектура.
Не нужно строить event streaming, если продукту достаточно GET после reconnect
Сложность должна соответствовать бизнесу.
Как выбирать interval для polling
Нет универсального:
5 секунд.Сначала определить бизнес-задержку.
Пользователь ждёт оплату:
2–3 секунды.Можно polling:
2 секунды.Но только пока открыт экран оплаты.
Dashboard
15–30 секунд.Статус доставки
60 секундили даже реже.
Долгий экспорт
Первые секунды:
2 secпотом:
5 secзатем:
10 sec.Так polling становится значительно дешевле
Long polling
Есть ещё вариант между polling и WebSocket.
Client отправляет:
GET /eventsServer не отвечает сразу.
Он держит request некоторое время.
Если появляется событие:
ответ.Client сразу открывает следующий request.
Это:
long polling.Сейчас его используют реже в новых browser systems
Потому что есть:
SSE;
WebSocket.Но как концепция он показывает важную вещь:
между обычным polling и постоянным socket существует несколько компромиссов.
Что выбрать небольшому продукту
Очень часто:
обычный HTTP
+
polling
+
webhooks внешних providersзакрывают почти все задачи.
Не нужно начинать проект с
WebSocket cluster
Redis Pub/Sub
message brokerтолько потому, что в будущем, возможно, появится чат.
Сначала реальная функция
Если чат появился:
добавляем WebSocket там,
где он действительно нужен.Можно одновременно использовать все три технологии
И это нормально.
Например SaaS:
статус background export.Webhook
платёжная система;
CRM;
email provider.чат клиента с менеджером;
живые уведомления.Это не архитектурный хаос
Это правильное использование инструментов по назначению.
Пример клиентского кабинета
Допустим заказчик хочет:
После сообщения менеджера клиент должен сразу увидеть новое сообщение.
WebSocket:
подходит.После оплаты счёта статус должен сразу стать «Оплачено».
Webhook:
provider → backend.Плюс WebSocket или polling:
backend → client UI.Статус длительной сборки архива должен обновляться.
Polling раз в:
3–5 секундможет быть достаточно.
Получается гибрид
Payment provider
│
│ webhook
▼
Backend
│
├── DB
│
├── WebSocket → browser
│
└── HTTP API ← pollingНе нужно искать один протокол для всей системы.
Что происходит при масштабировании WebSocket
На одном server всё просто.
При нескольких instances:
Load balancer
│
├── App 1
├── App 2
└── App 3WebSocket connection пользователя находится только на одном instance.
Событие может родиться на другом
Поэтому нужен механизм:
publish event
↓
all app instances / gateway
↓
нужный connection.Часто для этого появляется Redis
Например:
App 1
↓
Redis Pub/Sub
↓
App 3
↓
User.Но это не означает, что Redis нужен каждому приложению с WebSocket
При одном instance или небольшой архитектуре можно начать проще.
Важно понимать момент, когда появится необходимость.
WebSocket и sticky sessions
Иногда load balancer закрепляет пользователя за одним server.
Это может упростить connection handling.
Но не решает полностью:
как событие с App 2
попадёт пользователю на App 1.То есть distributed fan-out всё равно остаётся архитектурным вопросом.
WebSocket и авторизация
Нельзя просто открыть:
/wsи доверять client-provided:
projectId.Например пользователь подписывается:
project:1842.Backend обязан проверить:
имеет ли этот пользователь
доступ к project 1842?Иначе получается realtime IDOR
Пользователь меняет:
1842 → 1843и начинает получать чужие события.
Поэтому WebSocket authorization должна использовать те же правила, что HTTP API
Не отдельную упрощённую безопасность.
То же касается комнат
Например:
room = project:1842должна создаваться сервером на основании реальных permissions.
Не просто:
join whatever room client requested.Webhook security совсем другая
Здесь нет пользовательской session.
Нужно проверить:
кто внешний sender?Обычно используются:
HMAC signature;
timestamp;
secret;
event ID.Поэтому даже security model у технологий разная
Polling/WebSocket
user authentication
+
authorization.provider authentication
+
signature verification
+
replay protection.Как объяснить заказчику стоимость
Требование:
Пусть всё обновляется мгновенно.
может казаться одной небольшой функцией.
Но WebSocket-подсистема может добавить:
connection manager;
reconnect;
heartbeat;
message routing;
authorization;
Redis/broker;
monitoring;
load tests;
fallback sync.То есть стоимость разработки и эксплуатации вырастает.
Поэтому нужно спрашивать
Что бизнес потеряет, если обновление появится не через 200 мс, а через 5 секунд?
Если ответ:
Ничего.
Возможно, WebSocket не нужен.
А если ответ
Пользователь переписывается с оператором и пять секунд воспринимаются как тормоза.
Тогда real-time transport имеет реальную ценность.
Real time должно окупать сложность
Это, пожалуй, главный бизнес-принцип.
Нельзя выбирать технологию по моде
WebSocketне лучше polling сам по себе.
Так же как:
микросервисыне лучше монолита сами по себе.
Всё зависит от задачи.
Простая матрица выбора
| Задача | Polling | Webhook | WebSocket |
|---|---|---|---|
| Проверка статуса background job | Отлично | Нет | Иногда |
| Получение события от платёжной системы | Нет/дополнение | Отлично | Нет |
| Чат пользователей | Плохо на масштабе | Нет | Отлично |
| Обновление dashboard раз в 30 сек | Отлично | Нет | Избыточно |
| Синхронизация с CRM, если CRM умеет callback | Нет | Отлично | Нет |
| CRM без callback API | Отлично | Невозможно | Не решает источник |
| Живые уведомления в браузере | Иногда | Нет | Отлично |
| Статус доставки | Отлично | Отлично, если provider поддерживает | Обычно не источник |
| Совместное редактирование | Плохо | Нет | Отлично |
| Платёж + мгновенное обновление интерфейса | Polling UI | Webhook provider | WebSocket UI |
Как принимать решение по шагам
Вопрос 1. Где происходит событие?
Если внутри нашего backend:
WebSocket/SSE/polling.Если во внешней системе:
webhookесли она его предоставляет.
Вопрос 2. Может ли внешний сервис сам нас уведомить?
Да:
webhook.Нет:
polling external API.WebSocket нашего браузера здесь ничего не изменит.
Вопрос 3. Насколько критична задержка?
до минуты
→ polling
несколько секунд
→ polling часто достаточно
менее секунды
→ WebSocket/SSE кандидатЭто не жёсткие правила, а хорошая отправная точка.
Вопрос 4. Односторонняя или двусторонняя связь?
Только:
Server → Browserможно рассмотреть:
SSE.Активно:
Browser ⇄ ServerWebSocket выглядит естественнее.
Вопрос 5. Что происходит offline?
Если ответ:
Событие просто потеряется.
архитектура почти наверняка неполная.
Нужен:
database;
event log;
API resync;или другой durable source of truth.
Вопрос 6. Насколько часто происходят события?
раз в 10 минут— WebSocket, возможно, не нужен.
20 событий в секунду— polling, возможно, уже плохой выбор.
Вопрос 7. Сколько одновременно подключённых пользователей?
50и:
500 000— совершенно разные требования к WebSocket-инфраструктуре.
Что часто оказывается лучшим решением
Не:
выбрать одну технологию.А:
выбрать минимально сложную
для каждого отдельного потока данных.Чат
→ WebSocket
Платёж
→ webhook
Отчёт
→ polling
Server notification stream
→ SSEЭто называется не «разнобой»
Это нормальная архитектурная декомпозиция.
Важный сценарий: WebSocket disconnected, webhook пришёл
Представим пользователь находится на странице оплаты.
Socket разорвался.
В это время provider прислал:
payment.succeeded.Backend правильно сохранил:
PAID.Но browser не получил realtime event.
После reconnect интерфейс не должен оставаться в старом состоянии
Он делает:
GET /payment/currentи получает:
PAID.Именно поэтому HTTP API остаётся обязательным
Realtime transport ускоряет UX.
Не заменяет способность восстановить текущее состояние.
Ещё один сценарий: событие WebSocket пришло два раза
Например после reconnect/retry.
Frontend должен по возможности уметь обрабатывать:
duplicate notification.Например событие
{
"type": "message.created",
"messageId": 1842
}пришло дважды.
Если UI использует:
messageIdкак identity, второй event не создаёт второй message bubble.
То есть идемпотентность полезна даже в realtime UI
Не только в webhook.
Event payload лучше делать маленьким
Например WebSocket отправляет:
{
"type": "project.updated",
"projectId": 1842,
"revision": 17
}Frontend при необходимости обновляет объект.
Не обязательно отправлять огромный проект целиком
Особенно если:
project payload = 500 KB.При частых событиях это создаёт лишний network traffic.
Но дополнительный GET тоже имеет стоимость
Поэтому нужно выбирать между:
event = notification onlyи:
event = enough data to update UI.Это уже зависит от продукта.
Хорошо иметь event version/revision
Например frontend уже знает:
revision 18.Приходит:
revision 17.Можно игнорировать старое событие.
Это защищает от out-of-order даже внутри realtime layer
Потому что WebSocket одного соединения упорядочен на транспортном уровне, но данные могут приходить из:
нескольких backend processes;
workers;
reconnect;
разных источников.Domain revision всё равно полезна.
Что мониторить у WebSocket
Не только:
server is running.Полезны:
active_connections;
connections_opened;
connections_closed;
reconnect_rate;
messages_sent;
delivery_errors;
auth_failures.И heartbeat
Connection может технически существовать, но peer уже исчез.
Поэтому системы используют:
ping/pongили application heartbeat.
Но heartbeat не является бизнес-событием
Не нужно записывать:
каждый pingв основную БД.
Это эксплуатационный механизм.
Что мониторить у polling
Например:
requests/min;
unchanged response ratio;
client polling interval;
endpoint latency.Если:
99.9%ответов:
ничего не изменилось,возможно interval слишком агрессивный.
Что мониторить у webhook
received;
duplicates;
signature failures;
processing failures;
oldest pending;
delivery lag.Каждая технология имеет собственную эксплуатационную модель.
Не забывайте мобильные устройства
WebSocket на mobile web/PWA может разрываться при:
background;
sleep;
network change;
OS restrictions.Поэтому:
reconnect + resyncобязательны.
А если нужно уведомить пользователя, когда приложение закрыто?
WebSocket не поможет.
Закрытого приложения уже нет online.
Нужны:
Web Push;
FCM;
APNs;
native push notifications.Это ещё один важный пример
Заказчик говорит:
Нужно real time уведомление на телефон.
Разработчик отвечает:
Сделаем WebSocket.
Но если приложение закрыто:
socket отсутствует.Нужен push notification.
То есть real-time архитектура может включать
WebSocket
для online user
Push
для offline user
Database
для durable notification history.Один продукт — несколько delivery channels
Это нормально.
Можно ли сделать fallback
Да.
Например приложение сначала пытается:
WebSocket.Если соединение недоступно:
polling every 15 sec.Это повышает устойчивость.
Но fallback тоже нужно тестировать
Иначе он существует только на диаграмме.
Что выбрать для MVP
Очень часто:
polling.Почему?
Потому что позволяет быстро проверить продуктовую ценность без лишней realtime infrastructure.
Например новая система заявок
На старте:
админ dashboard
polling каждые 10 sec.Если через полгода оказывается, что администраторы реально постоянно работают в интерфейсе и мгновенные события повышают эффективность:
добавляем WebSocket.Это безопаснее, чем заранее строить сложную realtime-платформу без пользователей
Но чат — исключение
Если core feature продукта:
переписка в реальном времени,polling MVP может сразу создать неверное впечатление о качестве.
Там WebSocket имеет смысл с начала.
То есть MVP не означает «всегда polling»
МVP означает:
самая простая архитектура, которая всё ещё корректно проверяет ключевую ценность продукта.
Как переводить требование заказчика в техническое решение
Заказчик:
Хочу, чтобы всё было сразу.
Плохой ответ:
Тогда WebSocket.
Хороший диалог
Нужно спросить:
Что именно должно обновляться?Например:
Новые сообщения.
Какая допустимая задержка?Меньше секунды.
Кто создаёт событие?Другой пользователь нашего приложения.
Теперь:
WebSocketочень вероятно правильный выбор.
Другой пример
Нужно моментально видеть подтверждение платежа.
Спрашиваем:
Кто создаёт событие?ЮKassa/банк/payment provider.
Тогда:
provider → webhook → backend.И уже отдельно:
backend → browserчерез:
polling или WebSocket.Ещё пример
Хочу видеть изменение статуса груза сразу.
Provider:
не поддерживает webhook;
API обновляет статус каждые 10 минут.Можно построить сколько угодно WebSocket.
Данные всё равно не станут свежее десятиминутного source.
Это нужно честно объяснять заказчику
Скорость интерфейса не может быть выше скорости источника данных.
Если source обновляется:
раз в 15 минут,WebSocket способен мгновенно сообщить только:
старые данные.Поэтому SLA real time нужно определять end-to-end
Не только:
WebSocket latency = 50 ms.А:
событие произошло
↓
источник его зафиксировал
↓
мы узнали
↓
обработали
↓
отправили пользователю
↓
UI обновилсяНапример платёж
Provider processing:
700 ms
Webhook delivery:
300 ms
Backend processing:
100 ms
WebSocket:
50 ms
UI:
20 msИтого:
~1.17 sec.Вот это реальная latency функции.
Если webhook provider доставляет событие через 30 секунд
WebSocket:
50 msне спасёт.
«Реальное время» нужно измерять от бизнес-события
Не от последнего backend hop.
Полезно определить SLA
Например:
95% новых сообщений
видны получателю < 1 sec.или:
95% изменений статуса заказа
появляются < 30 sec.Теперь есть инженерная цель.
И её можно тестировать
Не:
Кажется быстро.
А:
event_created_at
→
ui_received_at.Стоимость ошибки тоже важна
Если dashboard опоздал на 20 секунд:
неприятно.Если потерян:
payment.succeededэто уже финансовый инцидент.
Поэтому webhook обычно требует более серьёзной надёжности, чем UI polling
Например:
подпись;
replay protection;
inbox;
dedupe;
reconciliation.Потому что речь может идти о business truth.
WebSocket event можно иногда потерять
Если после reconnect client делает full sync.
То есть надёжность каналов тоже различается
Webhook:
business event delivery
WebSocket:
low-latency UI notification
Polling:
state refreshИменно поэтому они часто работают вместе.
Архитектура сложного сценария
Например заказчик оплатил проект.
Payment provider
│
webhook
▼
Backend
│
┌───────┴────────┐
▼ ▼
Database WebSocket
│ │
│ ▼
│ Browser
│
└── REST API ← polling/resyncWebhook сообщает backend.
Database фиксирует истину.
WebSocket ускоряет UI.
REST API позволяет восстановить состояние.
Каждый инструмент делает свою работу.
Как не усложнить систему
Перед добавлением WebSocket полезно спросить:
- Нельзя ли решить задачу polling'ом раз в несколько секунд?
- Насколько пользователю заметна такая задержка?
- Сколько событий действительно происходит?
- Есть ли одновременно подключённые пользователи?
- Нужна ли двусторонняя realtime-связь?
- Как восстанавливать пропущенные события?
- Что произойдёт после restart server?
- Как масштабировать несколько instances?
- Нужны ли offline notifications?
- Есть ли бизнес-выгода от дополнительной сложности?
Если половина вопросов не имеет смысла для задачи, возможно WebSocket избыточен.
Перед webhook другие вопросы
- Поддерживает ли provider webhook?
- Как проверяется подпись?
- Может ли событие прийти дважды?
- Каков retry policy?
- Гарантируется ли порядок?
- Есть ли event ID?
- Можно ли получить текущее состояние через API?
- Что делать при пропущенном событии?
- Как долго хранить dedupe history?
- Что считать успешным приёмом?
Перед polling
- Какой interval действительно нужен?
- Можно ли его увеличивать со временем?
- Можно ли прекращать polling после terminal state?
- Нужно ли poll при скрытой вкладке?
- Сколько будет одновременных клиентов?
- Насколько дорог endpoint?
- Можно ли возвращать только изменения?
Тогда выбор становится инженерным
Не:
Что моднее?
А:
Какой механизм минимально сложен и удовлетворяет требованиям?
Понятная формула для заказчика
Можно объяснить так:
«Мы периодически спрашиваем сервер, не изменилось ли что-нибудь».
Просто.
Надёжно.
Есть небольшая задержка.
«Внешняя система сама сообщает нашему серверу, когда у неё что-то произошло».
Хорошо для:
платежей;
CRM;
доставки;
внешних сервисов.«Браузер держит постоянное соединение с нашим сервером, поэтому изменения можно отправлять пользователю практически мгновенно».
Хорошо для:
чатов;
живых уведомлений;
совместной работы;
интерактивных панелей.И очень важное дополнение
Иногда для одной функции нужны сразу два или три подхода.
Например платёж:
Webhook
→ backend узнаёт о платеже
WebSocket
→ пользователь видит его сразу
HTTP API
→ после reconnect подтверждаем текущее состояние.Что обычно стоит дороже
В простом проекте:
Polling
<
Webhook receiver
<
полноценная WebSocket infrastructureпо эксплуатационной сложности.
Но это не универсальная цена разработки.
Например надёжная платёжная webhook-система с:
signature;
replay;
dedupe;
reconciliationможет быть сложнее простого WebSocket notification channel.
Поэтому считать нужно конкретную функцию
Не технологию по названию.
Антипаттерн: realtime ради realtime
На dashboard есть:
число зарегистрированных пользователей.Оно меняется несколько раз в день.
Команда строит:
WebSocket subscription.Теперь:
connections;
Redis;
heartbeat;
reconnect;работают ради того, чтобы число:
142через несколько часов превратилось:
143на 20 секунд раньше.
Ценность:
почти нулевая.Сложность:
реальная.Другой антипаттерн: слишком частый polling
Чат:
GET /messages
every 500 ms.На:
20 000 users.Это попытка построить WebSocket с помощью HTTP requests.
Здесь уже лучше real-time transport.
Третий антипаттерн: webhook напрямую выполняет всё
Webhook
↓
update database
↓
generate PDF
↓
send email
↓
sync CRM
↓
notify Telegram
↓
20 sec
↓
200Provider получает timeout и отправляет событие повторно.
Теперь всё происходит дважды.
Лучше:
Webhook
↓
verify
↓
durable inbox
↓
200
↓
background jobs.Четвёртый антипаттерн: WebSocket является единственным источником состояния
Пользователь перезагрузил страницу.
Все предыдущие WebSocket events исчезли.
Если без них UI не может восстановиться:
архитектура сломана.Должен существовать обычный способ получить:
current state.Пятый антипаттерн: webhook принимается за push-уведомление пользователю
Webhook:
server → server.Push notification:
server → device.Это разные технологии.
Шестой антипаттерн: WebSocket для offline mobile
Закрытое приложение не держит обычный socket.
Нужна:
push infrastructure.Седьмой антипаттерн: polling без ограничения lifecycle
Страница job давно закрыта.
Browser tab скрыт.
Но каждые две секунды:
GET /statusпродолжается часами.
Так polling становится дорогим не из-за самой технологии, а из-за плохой реализации.
Как бы выглядело техническое решение для типового клиентского сервиса
Например есть:
личный кабинет;
чат;
заказы;
оплата;
уведомления;
файлы.WebSocket
+
durable messages in DB
+
REST resync.Оплата
payment webhook
+
idempotent processing
+
WebSocket notification
или короткий polling экрана оплаты.Новая заявка админу
Если требования умеренные:
polling 10 sec.Если администратор должен реагировать мгновенно:
WebSocket.Генерация архива
background job
+
polling 3–5 sec.WebSocket — только если UX действительно требует непрерывного progress.
provider webhook,если доступен.
Иначе:
scheduled polling provider API.Уведомления
database
+
WebSocket online
+
push offline.Получается гибридная, но логичная система.
Именно так строится зрелый real-time продукт
Не вокруг одной «мощной технологии».
А вокруг нескольких каналов с понятной ответственностью.
Простой decision tree
Откуда приходит событие?
/ \
внешний сервис наша система
│ │
Provider умеет webhook? │
/ \ │
да нет │
│ │ │
webhook polling │
provider provider API │
▼
Нужно обновить UI?
/ \
нет да
│
Допустима задержка?
/ \
да нет
│ │
polling WebSocket/SSEЭто намного ближе к реальной архитектуре, чем вопрос:
WebSocket или webhook?
В реальном времени должно быть то, что действительно требует реального времени
Например:
чатда.
онлайн presenceда.
совместное редактированиеда.
раз в сутки обновляемая статистиканет.
статус доставки,
который сам provider обновляет раз в часWebSocket ничего не ускорит.
Заказчику полезно знать ещё одну вещь
Каждый дополнительный realtime-механизм увеличивает не только стоимость разработки.
Но и:
стоимость тестирования;
мониторинга;
масштабирования;
поддержки;
диагностики инцидентов.Поэтому профессиональная архитектура не стремится использовать максимальное количество технологий.
Она стремится использовать минимально необходимый набор.
Что должно попасть в ТЗ
Если заказчик хочет real-time, одной формулировки:
Всё обновляется без перезагрузки.
недостаточно.
Лучше фиксировать:
какие события;
источник каждого события;
ожидаемая задержка;
что происходит offline;
нужно ли сохранять историю;
что происходит после reconnect;
есть ли внешние providers;
какой fallback.Вместо:
Сообщения работают в реальном времени.
Лучше:
После успешного сохранения сообщения получатель, находящийся online, должен получить уведомление о новом сообщении не позднее чем через 1 секунду при штатной работе инфраструктуры. После восстановления соединения клиент должен синхронизировать пропущенные сообщения через HTTP API.
Это уже проверяемое требование.
Вместо
Оплата отображается сразу.
Лучше:
Backend получает подтверждение оплаты через webhook платёжной системы. После фиксации успешного статуса открытый клиентский интерфейс уведомляется через realtime-канал либо обнаруживает изменение посредством временного polling. Текущее состояние оплаты всегда можно получить через API.
Теперь понятно:
кто;
что;
откуда;
как;Так архитектура становится проверяемой
Можно написать тест:
create message
↓
store
↓
event received
< 1 sec.Webhook:
payment event
↓
backend state = PAID
↓
duplicate event
↓
still one payment effect.Reconnect:
disconnect
↓
three messages created
↓
reconnect
↓
all three recovered.Без этого «real time» остаётся субъективным
Для одного заказчика:
10 секунд = сразу.Для другого:
500 мс = медленно.Поэтому latency должна стать частью требования.
Что выбрать первым
Для большинства обычных бизнес-приложений хорошее правило такое:
Начинайте с обычного HTTP и polling там, где задержка допустима.
Используйте webhook, когда внешний сервис умеет сам сообщать о событиях.
Добавляйте WebSocket или SSE там, где низкая задержка действительно влияет на пользовательский опыт.
Это позволяет не покупать сложность заранее.
А затем измерять
Если polling endpoint получает:
миллионы пустых requests,можно переходить на push-модель.
Если пользователи не замечают:
5 секунд задержки,не нужно ничего усложнять.
Архитектура должна эволюционировать вместе с нагрузкой
Например:
MVP
pollingзатем:
рост
WebSocket notificationsзатем:
несколько app instances
Redis Pub/Subзатем, если действительно понадобится:
специализированный event infrastructure.Не обязательно строить последний этап в первый день проекта.
Вместо вывода
Polling, webhook и WebSocket не являются тремя конкурирующими способами сделать одно и то же.
Они решают разные задачи.
Polling означает:
клиент сам спрашивает,
изменилось ли состояние.Он прост и отлично работает там, где небольшая задержка допустима.
Webhook означает:
внешняя система
сама сообщает нашему backend,
что у неё произошло событие.Он незаменим для платежей, CRM, доставки и других server-to-server интеграций.
WebSocket означает:
между клиентом и сервером
поддерживается постоянное соединение,
по которому события можно доставлять
с минимальной задержкой.Он полезен для чатов, presence, совместной работы и действительно интерактивных интерфейсов.
При этом хороший продукт часто использует их вместе.
Например:
Платёжная система
│
webhook
▼
Backend
│
├── Database
│
├── WebSocket
│ ↓
│ Browser
│
└── HTTP API
↑
polling /
reconnect syncПоэтому требование:
Сделайте всё в реальном времени.
нужно сначала перевести с языка пожеланий на язык системы:
Что именно изменяется?
Кто создаёт событие?
Кому нужно его увидеть?
Как быстро?
Можно ли пропустить?
Что происходит offline?
Есть ли внешний provider?И только после этого выбирать технологию.
Иногда правильный ответ будет:
WebSocket.Иногда:
webhook.Иногда:
обычный polling раз в 10 секунд.А иногда — комбинация всех трёх.
Профессиональная архитектура определяется не количеством realtime-технологий.
Она определяется тем, что каждый поток данных использует самый простой механизм, который обеспечивает нужную скорость, надёжность и пользовательский опыт.