Архитектура real-time систем: WebSocket, SSE и Long Polling

Архитектура real-time систем: WebSocket, SSE и Long Polling

В современном вебе интерактивность стала стандартом. Пользователи ожидают мгновенных уведомлений в чатах, обновления курсов акций в реальном времени, изменения статусов заказов и плавную анимацию игровых событий. Традиционная модель HTTP «запрос-ответ» (Request-Response) идеально подходит для загрузки страниц или получения данных из БД по запросу, но она не предназначена для ситуаций, когда сервер должен сам «толкать» данные клиенту в момент их появления.

Для решения этой задачи архитекторы используют три основных подхода: Long Polling, Server-Sent Events (SSE) и WebSockets. В этой статье мы разберем технические нюансы каждого метода, их сильные и слабые стороны, а также критерии выбора подходящего решения для вашего проекта.

1. Long Polling: Классика с ограничениями

Long Polling — это техника, имитирующая push-уведомления в рамках стандартного протокола HTTP. Клиент отправляет запрос к серверу, и сервер не отвечает сразу. Он «держит» соединение открытым до тех пор, пока не появятся новые данные или не истечет тайм-аут.

Как только сервер получает данные (или время вышло), он отправляет ответ, и клиент тут же инициирует новый запрос.

Преимущества:

  • Поддержка всеми браузерами (даже самыми старыми).
  • Работает через стандартные HTTP-прокси и фаерволы.

Недостатки:

  • Значительный оверхед: каждый новый запрос требует повторной передачи заголовков (headers), что нагружает сеть при частом обновлении данных.
  • Задержка: между получением ответа и отправкой нового запроса есть микрозадержка.

Когда использовать: Сегодня Long Polling используется редко, в основном как fallback-метод для старых систем или когда обновления происходят редко (например, раз в несколько минут).

2. Server-Sent Events (SSE): Эффективный односторонний поток

SSE — это стандарт, позволяющий серверу удерживать HTTP-соединение открытым и транслировать данные клиенту в виде потока данных. В отличие от Long Polling, здесь не нужно постоянно создавать новые запросы.

Протокол очень прост: сервер устанавливает заголовок Content-Type: text/event-stream и отправляет текстовые сообщения в формате data: сообщение\n\n.


// Пример обработки SSE на Node.js (упрощенно)
app.get('/events', (req, res) => {
    res.setHeader('Content-Type', 'text/event-stream');
    res.setHeader('Cache-Control', 'no-cache');
    res.setHeader('Connection', 'keep-alive');

    // Отправка данных клиенту по мере их появления
    setInterval(() => {
        res.write(`data: ${JSON.stringify({ message: 'Новое уведомление' })}\n\n`);
    }, 5000);
});