SSE vs WebSockets: разобрались, что где лучше работает
Марк Садыков, главный инженер по разработке в Сбере и ментор Эйч Навыки, рассказывает, что такое SSE и WebSockets и как они используются, и дает советы для прохождения собеседований.
221 открытий2К показов
Сегодня в веб-разработке есть много технологий для обмена данными между сервером и клиентом в реальном времени. Среди них особое место занимают SSE (Server-Sent Events) и WebSockets. Обе технологии позволяют создавать динамичные приложения, такие как чаты, онлайн-игры или панели мониторинга. Но они работают по-разному и подходят для разных задач.
Вместе с Марком Садыковым, главным инженером по разработке в Сбере и ментором Эйч Навыки, разбираемся как работают SSE и WebSockets, чем они отличаются и даже как ответить на вопросы о них на собеседовании.
Что такое WebSockets и SSE и как они работают на базовом уровне?
Существуют 4 главные стратегии общения клиента и сервера в реальном времени: WebSocket, Server-Sent Events, Long Polling и Short Polling. Нужно четко понимать различие в стратегиях, чтобы построить быстрое и поддерживаемое приложение, хотя и принято в любой непонятной ситуации использовать WebSocket.
WebSocket — протокол связи поверх TCP-соединения для обмена сообщениями между клиентом и сервером, он использует постоянное соединение.
SSE (Server-Sent Events) — push-технология (связь инициируется сервером, а не клиентом), позволяющая клиенту получать автоматические обновления с сервера через HTTP-соединения.
Эти технологии позволяют поддерживать постоянное соединение между клиентом и сервером для обмена данными в реальном времени. Информация передается и обновляется мгновенно или почти мгновенно с учетом физических задержек сети. Это особенно полезно в приложениях, где важна минимальная задержка в передаче данных: чаты, онлайн-игры, уведомления. Безусловно реальное время можно реализовать посредством Long Polling и Short Polling, но это потребует больше ресурсов разработки, дальнейшей поддержки, плюс это довольно сложно сделать эффективно.
Вот как это выглядит в виде схемы:
WebSocket
SSE
Long Pooling
Short Pooling
В общем случае для реального времени в вебе лучше использовать WebSocket и SSE.
WebSocket можно сравнить с телефонным разговором. Когда вы звоните другу, вы устанавливаете связь (как начальный Handshake в WebSocket). После этого линия остается постоянно открытой, и вы можете говорить друг с другом долго, не прерывая разговор и не набирая номер заново для каждого слова. Вы оба можете говорить и слушать одновременно (двусторонняя связь), и все, что вы говорите, доходит до собеседника мгновенно. Если вдруг сигнал теряется, вы можете перезвонить.
SSE можно сравнить с подпиской на журнал. Вы подписываетесь один раз, после этого издатель сам отправляет вам новые выпуски каждый месяц, как только они выходят. Вам не нужно каждый раз звонить издателю и спрашивать, не вышел ли новый выпуск — журнал просто приходит по подписке, и вы получаете его, как только он доступен.
Принцип работы WebSocket
Установка соединения (WebSocket Handshake)
Соединение WebSocket начинается с WebSocket Handshake, который является специальным начальным HTTP-запросом, инициируемым клиентом. Этот запрос содержит особые заголовки, указывающие, что клиент хочет переключиться на WebSocket-протокол. Основные этапы процесса Handshake:
- Клиент отправляет HTTP-запрос с методом
GET
на сервер и заголовком
, который указывает серверу желание переключиться с HTTP на WebSocket-протокол.Upgrade
: websocket - Заголовок
Connection:
подтверждает намерение перейти на другой протокол.Upgrade
- В заголовке
Sec-WebSocket-Key
клиент отправляет случайную строку, которая будет использоваться сервером для создания уникального ключа для данного соединения.
- Сервер отвечает с кодом статуса 101 Switching Protocols, если поддерживает WebSocket. Далее включает заголовок
Sec-WebSocket-Accept
, в котором находится подтвержденный ключ.
- После успешного
Handshake
соединение переходит в WebSocket-протокол. Клиент и сервер теперь могут обмениваться данными в рамках постоянного соединения.
Запрос от клиента:
Ответ сервера:
Ключ безопасности в заголовке Sec-WebSocket-Accept
генерируется сервером на основе ключа клиента Sec-WebSocket-Key
с использованием следующего алгоритма:
- Сервер берет значение Sec-WebSocket-Key, добавляет к нему фиксированную строку
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
- Результат хэшируется с помощью SHA-1
- Полученный хэш преобразуется в формат Base64 и отправляется клиенту в заголовке
Sec-WebSocket-Accept
Передача данных
После установки соединения WebSocket данные передаются в виде фреймов — компактных порций данных, которые могут быть отправлены в любом направлении. Фреймы WebSocket минимальны по размеру, что позволяет сократить объем передаваемых данных и уменьшить задержку.
- Фреймы данных: каждый фрейм включает служебную информацию (например, флаги начала и конца сообщения), а также полезную нагрузку (payload), содержащую данные.
- Типы фреймов: WebSocket поддерживает несколько типов фреймов, включая текстовые (обычно в формате JSON) и бинарные (например, для передачи изображений или других медиаданных), что позволяет передавать данные любого формата.
- Фреймы управления: используются для закрытия соединения, проверки активности соединения (ping/pong), а также других служебных задач.
Принципы работы SSE
Установка соединения SSE через HTTP/2
Рассмотрим установку соединения HTTP/2, поскольку эта версия наиболее популярная. У нас есть веб-приложение, которое должно получать уведомления о состоянии сервера в режиме реального времени. Клиент инициирует подключение с сервером, чтобы подписаться на эти события. При использовании HTTP/2 устанавливается одно TCP-соединение для всего обмена данными между клиентом и сервером, включая как SSE-события, так и обычные HTTP-запросы.
Запрос клиента:
- Клиент отправляет обычный
-запрос на сервер, чтобы подписаться на поток событий (с заголовкомGET
Accept: text/event-stream
, указывающим, что он ожидает поток SSE).
- HTTP/2 позволяет использовать одно TCP-соединение для всех взаимодействий клиента с сервером, что исключает необходимость в открытии новых соединений и снижает нагрузку на сеть.
Ответ сервера и поток данных в формате SSE
Сервер принимает запрос и начинает отправлять данные в формате text/event-stream
. Благодаря мультиплексированию HTTP/2 сервер может отправлять этот поток данных одновременно с другими ресурсами (CSS, JavaScript), используя одно и то же соединение.
Ответ сервера:
После этого сервер начинает отправлять события в формате SSE, например, обновления состояния сервера или уведомления о новых событиях.
Формат события SSE
События SSE передаются в виде текста, где каждое событие завершается пустой строкой для разделения сообщений. Вот пример данных, которые сервер может отправлять клиенту:
Управление соединением и автоматическое переподключение
Если соединение разрывается, браузер автоматически попытается переподключиться. В HTTP/2 переподключение происходит быстрее, так как открывается всего одно TCP-соединение, которое поддерживает все потоки данных, включая SSE.
Пример с поддержкой Last-Event-ID
:
- Клиент может отправить заголовок
Last-Event-ID
при переподключении, чтобы сообщить серверу, на каком событии он остановился.
- Сервер может продолжить отправку событий с нужного ID, что предотвращает потерю данных при разрыве соединения. Данные будут отправляться с нужного события.
Запрос клиента на переподключение с Last-Event-ID
Производительность
1. WebSocket и высокая нагрузка
WebSocket создают постоянные двусторонние соединения, что приводит к специфическим требованиям для обработки большого количества подключений.
Влияние на производительность и потребление ресурсов
- Использование памяти и CPU. Поскольку WebSockets поддерживают постоянные соединения, каждый подключенный клиент занимает ресурсы сервера (память, процессорное время, сокеты).
- Потребление сетевых ресурсов. WebSocket соединения могут передавать данные часто и с высокой скоростью, что увеличивает сетевой трафик. Кроме того, WebSockets передают
ping/pong
пакеты для проверки активности соединения, что также требует ресурсов. - Энергопотребление на мобильных устройствах. Постоянное соединение и активный обмен данными приводят к увеличению энергопотребления на устройствах пользователей, особенно на мобильных, так как устройство должно часто выходить в сеть для поддержания соединения.
2. SSE и высокая нагрузка
SSE — это однонаправленный протокол, который отправляет данные от сервера к клиенту по открытому HTTP-соединению.
Влияние на производительность и потребление ресурсов
- Меньше потребление памяти и CPU. SSE поддерживает только однонаправленное соединение, что снижает нагрузку на процессор и память по сравнению с WebSockets.
- Оптимизированная работа в сетях. SSE использует HTTP и работает на стандартных портах, что облегчает работу через прокси и балансировщики нагрузки и позволяет эффективнее использовать сетевые ресурсы.
- Энергопотребление. SSE менее требователен к батарее на мобильных устройствах, так как поддерживает постоянное соединение без дополнительных проверок активности (например,
ping/pong
).
Когда лучше использовать WebSockets, а когда SSE?
Выбор между WebSockets и Server-Sent Events (SSE) зависит от требований конкретного приложения и от того, как данные должны передаваться между клиентом и сервером.
Когда лучше использовать WebSockets
WebSockets подходят для сценариев, когда требуется двусторонняя связь между клиентом и сервером. Это идеальный выбор, если приложение должно отправлять данные как от клиента к серверу, так и от сервера к клиенту в режиме реального времени.
- Приложения с высокой интерактивностью и двусторонней связью. WebSockets идеально подходят для чатов, игр, и финансовых платформ, где пользователи взаимодействуют друг с другом и отправляют данные на сервер с минимальной задержкой.
- Сценарии с частыми и неограниченными обновлениями. WebSockets поддерживают постоянное двустороннее соединение, что позволяет обмениваться данными в любой момент.
- Сложные интерфейсы с большим объемом данных. Если приложение постоянно получает или отправляет данные в обе стороны (платформа для мониторинга в реальном времени с большим количеством пользователей).
- Работа с бинарными данными. WebSockets поддерживают как текстовые, так и бинарные данные, что делает их подходящими для мультимедийных приложений, передающих изображения, видео или файлы.
- Низкая задержка и критичность времени отклика. В сценариях, где задержка в миллисекунды может влиять на пользовательский опыт, например, в торговых платформах, WebSockets позволяют передавать данные в реальном времени с минимальной задержкой.
Когда лучше использовать Server-Sent Events (SSE)
SSE с его однонаправленным подключением лучше всего подходит для приложений, где сервер должен отправлять данные клиенту, но не требуется ответных сообщений от клиента в реальном времени.
- Приложения с однонаправленным потоком данных от сервера к клиенту. SSE хорошо подходит для лент новостей, уведомлений, ценовых обновлений и других данных, которые сервер отправляет клиенту без необходимости получать ответы.
- Сценарии с меньшими требованиями к частоте обновления. Если данные обновляются с предсказуемой или средней частотой, SSE достаточно для поддержания потока.
- Поддержка автоматического переподключения и восстановления после разрывов. SSE автоматически восстанавливает соединение, если оно разрывается, и не требует сложной логики на стороне клиента.
- Энергосбережение на мобильных устройствах. SSE менее требователен к энергии на мобильных устройствах, чем WebSockets, так как оно не требует постоянного пинга для поддержания соединения.
- Поддержка стандартных сетей и кэширования. SSE работает поверх HTTP и использует текстовые данные, что упрощает поддержку в корпоративных сетях и через прокси-серверы.
WebSocket и SSE: собеседования по проектированию
На собеседованиях по проектированию часто обсуждают выбор технологий для реализации приложений в реальном времени.
Рассмотрим несколько кейсов на собеседованиях
Объясните, как бы вы спроектировали архитектуру для системы уведомлений/чата/игры с помощью WebSocket или SSE.
Контекст: Интервьюер может попросить кандидата представить архитектуру для приложения, требующего передачи данных в реальном времени, и объяснить выбор между WebSocket и SSE.
Пример ответа:
- Для системы чата я выбрал бы WebSocket, так как требуется двусторонняя связь. Я бы организовал кластер серверов с балансировщиком нагрузки, поддерживающим постоянные соединения. Для синхронизации сообщений между серверами я бы использовал Redis как брокер сообщений.
- Для системы уведомлений я бы выбрал SSE, так как требуется только передача данных от сервера к клиенту. Используя HTTP/2, можно мультиплексировать несколько потоков на одном соединении.
Как WebSocket и SSE ведут себя в условиях плохого интернет-соединения?
Контекст: Понимание устойчивости соединений при нестабильной сети важно для проектирования пользовательского опыта.
Примеры ответа:
- WebSocket требует ручного переподключения при разрыве связи, поэтому для устойчивости можно реализовать автоматическое переподключение с сохранением состояния. Это добавляет сложности к архитектуре, но необходимо для обеспечения стабильной работы.
- SSE автоматически переподключается при разрыве, и клиент может использовать
Last-Event-ID
, чтобы сервер мог продолжить отправку событий с последнего места.
Как выбрать WebSocket или SSE в зависимости от требований производительности и ресурсов?
Контекст: Интервьюер может предложить кейс, в котором необходимо выбрать технологию с учетом ограничений по ресурсам и высокой нагрузке.
Пример ответа:
- WebSocket больше подходит для приложений с высокой интерактивностью, но требует значительных ресурсов, так как каждое подключение занимает память и процессорные ресурсы на сервере. SSE более экономичен, так как не требует двустороннего соединения и легче масштабируется, но не подходит для сценариев, где нужно передавать данные от клиента к серверу в реальном времени.
Архитектурные примеры для реальных проектов
Пример для WebSocket:
- Чат-приложение: Архитектура включает WebSocket-сервер, работающий с Redis для синхронизации сообщений между узлами. Каждый узел поддерживает постоянные соединения с клиентами. Для балансировки нагрузки используются специализированные балансировщики, такие как Nginx или HAProxy, а для хранения сообщений — базы данных с поддержкой очередей (например, RabbitMQ или Redis).
Пример для SSE:
- Новостное приложение: Архитектура включает HTTP/2-сервер для поддержки SSE и отправки обновлений новостей. Сервер поддерживает CORS и отправляет данные только авторизованным пользователям. Для масштабирования используется балансировщик нагрузки, а каждое соединение работает через HTTP/2, что позволяет передавать данные без дополнительных соединений.
WebSockets и SSE — это одни из ключевых технологий для работы с данными в реальном времени. WebSockets подходят для сложных, интерактивных приложений с двусторонней связью, таких как чаты или игры, тогда как SSE — отличный выбор для простых потоков данных от сервера к клиенту, например, уведомлений или лент новостей. Понимание их различий поможет выбрать подходящее решение и оптимизировать ваш проект.
221 открытий2К показов