Server-Sent Events vs WebSockets: выбор технологии реального времени
Потребность в коммуникации реального времени
Традиционный HTTP работает по модели запрос-ответ: клиент спрашивает, сервер отвечает. Но современные веб-приложения требуют обновлений в реальном времени — live-дашборды, чат, уведомления, биржевые котировки, алерты мониторинг сайтов. Две технологии решают эту задачу: Server-Sent Events (SSE) и WebSockets. Выбор зависит от сценария использования.
Server-Sent Events (SSE)
SSE — простой протокол на основе HTTP для потоковой передачи обновлений от сервера к клиенту. Клиент открывает стандартное HTTP-соединение, сервер отправляет события по мере их возникновения. Соединение остаётся открытым, браузер автоматически переподключается при обрыве.
// Клиент: JavaScript EventSource API
const source = new EventSource('/api/events');
source.onmessage = (event) => {
const data = JSON.parse(event.data);
updateDashboard(data);
};
source.addEventListener('alert', (event) => {
showNotification(JSON.parse(event.data));
});
// Сервер: PHP SSE endpoint
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
header('X-Accel-Buffering: no');
while (true) {
$data = getLatestUpdates();
if ($data) {
echo "event: update\n";
echo "data: " . json_encode($data) . "\n\n";
}
ob_flush();
flush();
sleep(1);
}
Особенности SSE:
- Однонаправленный — только от сервера к клиенту. Клиент отправляет данные обычными HTTP-запросами
- Автоматическое переподключение — браузер сам обрабатывает переподключение с настраиваемыми интервалами
- ID событий — сервер присваивает ID; при переподключении браузер отправляет последний ID для возобновления
- Текстовый — события в UTF-8 (обычно JSON). Нет поддержки бинарных данных
- Стандартный HTTP — работает через прокси, балансировщики, CDN без специальной настройки
WebSockets
WebSockets обеспечивают полнодуплексную коммуникацию по одному TCP-соединению. После HTTP upgrade handshake и клиент, и сервер могут отправлять сообщения в любое время. Протокол поддерживает текстовые и бинарные данные.
// Клиент: WebSocket API
const ws = new WebSocket('wss://example.com/ws');
ws.onopen = () => {
ws.send(JSON.stringify({ type: 'subscribe', channel: 'alerts' }));
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
handleMessage(data);
};
ws.onclose = () => {
// Нужно ручное переподключение
setTimeout(() => reconnect(), 3000);
};
Особенности WebSockets:
- Двунаправленный — клиент и сервер могут отправлять сообщения независимо
- Поддержка бинарных данных — эффективная передача изображений, файлов, protocol buffers
- Низкие накладные расходы — после handshake фреймы имеют всего 2–14 байт overhead
- Нет автоматического переподключения — логику переподключения нужно реализовать самостоятельно
- Кастомный протокол — требует WebSocket-совместимых прокси и балансировщиков
Сравнение
| Свойство | SSE | WebSockets |
|---|---|---|
| Направление | Сервер → Клиент | Двунаправленное |
| Протокол | HTTP/1.1, HTTP/2 | WS/WSS (upgrade из HTTP) |
| Формат данных | Текст (UTF-8) | Текст + Бинарные |
| Переподключение | Автоматическое | Ручное |
| Макс. соединений | 6 на домен (HTTP/1.1) | Без HTTP-ограничений |
| Поддержка прокси/CDN | Отличная | Требует настройки |
| Сложность | Простая | Выше |
| Масштабируемость | Проще (stateless HTTP) | Сложнее (stateful соединения) |
Когда использовать SSE
- Дашборды мониторинга — сервер отправляет метрики, статусы и алерты в браузер. Enterno.io использует подобные паттерны для отображения мониторинга в реальном времени
- Новостные ленты и уведомления — сервер отправляет новые элементы по мере появления
- Обновления прогресса — длительные задачи отправляют процент выполнения
- Живые логи — потоковая передача записей логов в веб-просмотрщик
- Биржевые котировки / спортивные результаты — серверные данные для отображения клиентами
Когда использовать WebSockets
- Чат — оба пользователя отправляют сообщения одновременно
- Совместное редактирование — реальное совместное редактирование в стиле Google Docs
- Онлайн-игры — двунаправленная коммуникация с низкой задержкой и бинарными данными
- Торговые платформы — быстрое размещение ордеров и получение рыночных данных
- Видео/аудио сигнализация — WebRTC signaling требует двунаправленных сообщений
Производительность
- Лимит соединений — HTTP/1.1 ограничивает браузеры 6 соединениями на домен. SSE занимает одно из них. HTTP/2 мультиплексирует потоки, снимая ограничение
- Использование памяти — каждое WebSocket-соединение хранит состояние на сервере. 10 000 пользователей = 10 000 stateful соединений. SSE через HTTP/2 эффективнее по памяти
- Балансировка нагрузки — WebSocket-соединения «липкие» — должны маршрутизироваться на один backend. Это усложняет масштабирование. SSE проще балансировать
- Сжатие — SSE использует стандартное HTTP-сжатие (gzip/Brotli). Сжатие WebSocket (permessage-deflate) добавляет нагрузку на CPU
Советы по реализации
- Для SSE отключите буферизацию в nginx (
X-Accel-Buffering: no,proxy_buffering off) - Для WebSockets настройте reverse proxy на поддержку заголовка Upgrade и увеличьте таймауты
- Обе технологии нуждаются в heartbeat для обнаружения мёртвых соединений
- Используйте брокер сообщений (Redis Pub/Sub, Kafka) для распределения событий между инстансами
- Для PHP-приложений SSE проще — использует стандартный HTTP. WebSockets обычно требуют отдельный серверный процесс
Заключение
SSE и WebSockets решают разные задачи. SSE — правильный выбор для потоковой передачи от сервера к клиенту: проще, работает со стандартной HTTP-инфраструктурой, автоматически переподключается. WebSockets необходимы при двунаправленной коммуникации или передаче бинарных данных. Для большинства задач мониторинга и уведомлений SSE — прагматичный выбор. Используйте WebSockets когда двунаправленность — реальное требование, а не кажущееся.
Проверьте ваш сайт прямо сейчас
Проверить →