WebSocket SSE и polling: как выбрать способ обновления данных

Когда перед разработчиком встает задача сделать интерфейс «живым» — чтобы уведомления прилетали мгновенно, а котировки акций менялись без перезагрузки страницы — первым делом в голову приходят WebSocket или SSE. Но опытный архитектор сначала спросит: «А точно ли нам не хватит обычного опроса по таймеру?».
Выбор технологии обновления данных — это всегда компромисс между UX, нагрузкой на инфраструктуру и сложностью поддержки. В этой статье мы разберем три основных подхода, разберем их «подкапотную» часть и определим, какой инструмент в какой ситуации будет оптимальным.
1. Short Polling: Старый добрый опрос
Short Polling (короткие опросы) — это самый примитивный способ. Клиент просто отправляет HTTP-запрос на сервер через равные промежутки времени (например, раз в 5 секунд): «Есть что-то новое?». Сервер отвечает либо актуальными данными, либо пустым ответом.
Как это работает на практике
Это обычный REST-запрос. Клиент делает GET /api/updates, получает JSON, закрывает соединение. Через $N$ секунд повторяет процедуру.
Плюсы:
- Максимальная простота. Не нужно настраивать специфические серверные модули, прокси-серверы или балансировщики.
- Отказоустойчивость. Если один запрос упал, следующий просто повторится. Нет состояния «разрыва сессии», которое нужно обрабатывать.
- Кэширование. Ответы можно кэшировать на уровне HTTP-прокси или CDN.
Минусы:
-
- Огромный оверхед. Каждый запрос — это полноценный HTTP-пакет с заголовками. Если у вас 10 000 пользователей, которые стучатся раз в секунду, сервер будет тратить больше ресурсов на обработку TCP-хендшейков и парсинг заголовков, чем на полезную работу с базой данных.
-
- Задержка (Latency). Если обновление произошло сразу после запроса, пользователь увидит его только через 4.9 секунды (при интервале в 5с).
-
- Лишняя нагрузка на БД. Сервер будет выполнять тысячи запросов «ни о чем», когда данных на самом деле нет.
2. Long Polling: Эволюция опроса
Long Polling — это попытка сделать опрос более эффективным. Суть в том, что сервер не отвечает сразу, если новых данных нет. Он «придерживает» запрос до тех пор, пока данные не появятся или не выйдет таймаут.
Механика процесса:
- Клиент отправляет запрос.
- Сервер держит соединение открытым.
- Как только в базе появилось обновление, сервер отправляет ответ.
- Клиент получает данные и тут же отправляет новый запрос, чтобы снова ждать обновлений.
В чем профит по сравнению с Short Polling?
-
- Снижение задержки. Данные приходят почти мгновенно в момент их появления.
-
- Меньше пустых ответов. Мы не спамим сервер бессмысленными запросами каждые несколько секунд.
Где начинаются проблемы?
Главная беда Long Polling — управление соединениями. Если у вас тысячи открытых «висящих» запросов, вы быстро упретесь в лимиты по количеству открытых соединений на сервере или в ограничениях веб-сервера (например, лимиты рабочих потоков в Apache).
3. Server-Sent Events (SSE): Односторонний поток
SSE — это стандарт, который позволяет серверу «стримить» данные клиенту по одному HTTP-соединению. Это фактически односторонний канал: сервер пишет, клиент слушает.
Техническая реализация
SSE использует специальный заголовок Content-Type: text/event-stream. Соединение открывается один раз, и сервер может отправлять сообщения в любое время.
Почему SSE часто лучше, чем кажется:
- Автоматическое переподключение. Браузер сам пытается восстановить связь, если соединение оборвалось. Вам не нужно писать сложную логику реконнекта вручную.
- Легкость. Это обычный HTTP. Вам не нужно менять протоколы, настраивать специфические порты или бороться с особенностями прокси-серверов, которые могут резать WebSocket-трафик.
- Экономия ресурсов. Нет постоянных циклов «запрос-ответ». Один раз установили связь — и получаем поток данных.
Ограничения SSE:
-
- Только в одну сторону. Клиент не может отправить сообщение через этот же канал. Для этого придется делать обычные POST-запросы.
-
- Лимиты браузеров. В старых браузерах (или при использовании HTTP/1.1) есть лимит на количество одновременных соединений с одним доменом (обычно до 6). Если пользователь откроет 6 вкладок с вашим приложением, седьмая просто не загрузится. Решается переходом на HTTP/2.
4. WebSockets: Полноценный двусторонний канал
WebSocket — это полноценный двусторонний (full-duplex) протокол. После «рукопожатия» (Handshake) по HTTP, соединение переключается на протокол ws:// (или wss://), и теперь и клиент, и сервер могут слать данные друг другу в любой момент без лишних заголовков.
Когда это необходимо:
-
- Чаты и мессенджеры. Где общение идет в обе стороны с высокой интенсивностью.
-
- Коллаборативные редакторы. (Например, Google Docs или Figma), где каждое движение курсора другого пользователя должно быть видно мгновенно.
-
- Онлайн-игры. Где задержка в 100 мс может быть критичной.
Обратная сторона медали (Сложности):
- Сложность инфраструктуры. Балансировщики нагрузки (Nginx, HAProxy) нужно специально настраивать для поддержки WebSocket.
- Stateful-природа. Сервер должен «помнить», какой клиент к нему подключен. Это усложняет горизонтальное масштабирование. Если у вас 3 сервера, и клиент А подключен к серверу 1, а сообщение ему шлет клиент Б через сервер 2, вам понадобится промежуточный слой (например, Redis Pub/Sub), чтобы доставить сообщение.
- Здоровье соединения. Вам придется вручную реализовывать Heartbeat (ping/pong), чтобы понимать, что клиент всё еще в сети, а не «отвалился» по таймауту провайдера.
Сравнительная таблица для быстрого выбора
| Критерий | Short Polling | Long Polling | SSE | WebSockets |
|---|---|---|---|---|
| Направление | Клиент $\rightarrow$ Сервер | Клиент $\rightarrow$ Сервер | Сервер $\rightarrow$ Клиент | Двустороннее |
| Нагрузка на сеть | Очень высокая | Средняя | Низкая | Самая низкая |
| Реализация | Тривиальная | Средняя | Простая | Сложная |
| Реконнект | Не нужен | Вручную | Автоматически | Вручную |
| Протокол | HTTP | HTTP | HTTP | WS / WSS |
Итоговый алгоритм выбора (Checklist)
Чтобы не ошибиться с выбором, пройдите по этому списку вопросов:
Нужно ли клиенту отправлять данные так же часто, как получать их?
-
- Да $\rightarrow$ Ваш выбор WebSockets.
-
- Нет $\rightarrow$ Переходим к вопросу 2.
Обновления происходят редко (раз в несколько минут или часов) и критичность задержки низкая?
-
- Да $\rightarrow$ Используйте Short Polling. Это проще всего и надежнее всего в поддержке.
-
- Нет $\rightarrow$ Переходим к вопросу 3.
Данные должны приходить мгновенно, но отправка от клиента идет редко (редкие действия)?
-
- Да $\rightarrow$ Используйте SSE. Это легче в реализации, чем WebSocket, и работает стабильнее через прокси.
-
- Нет (нужна почти мгновенная реакция в обе стороны) $\rightarrow$ WebSockets.
Вы работаете в очень старой инфраструктуре, где запрещены любые соединения, кроме стандартного HTTP?
-
- Да $\rightarrow$ Long Polling.
Резюме от автора
Частая ошибка новичков — внедрение WebSockets везде, где только можно. Это создает огромную техническую нагрузку на поддержку и усложняет деплой.
Если вам нужно просто уведомлять пользователя о том, что «заказ готов» или «пришло новое письмо» — SSE будет идеальным выбором. Он дает почти ту же скорость, что и сокеты, но не заставляет вас переписывать всю конфигурацию сервера и бороться с обрывами соединений. Оставляйте WebSockets только для тех случаев, когда вы строите настоящий интерактив в реальном времени.

