От автора: в приложениях реального времени само собой разумеется, что нам нужно получать информацию с серверов, как только она станет доступной — и, по сути, классическая парадигма HTTP — запрос/ответ не подходит. Это потому, что сервер будет молчать, есть ли новые данные или нет, до тех пор, пока не будет отправлен запрос.
Это ограничение привело к появлению всевозможных хаков и обходных решений, поскольку разработчики стремились адаптировать модель запроса/ответа к требованиям более динамичной сети реального времени, некоторые из которых стали формализованными и довольно широко распространенными.
Все эти технологии и подходы — от Comet до длинного поллинга HTTP — имеют одну общую черту: по сути, они призваны создать иллюзию реального (событийного) обмена данными, поэтому, когда на сервере появляются какие-то новые данные, он отправляет ответ.
Несмотря на то, что HTTP не является протоколом, управляемым событиями, не в реальном времени, эти подходы на самом деле работают довольно хорошо в определенных случаях использования, например, в чате Gmail. Однако проблемы возникают в приложениях с малой задержкой или масштабировании, в основном из-за требований к обработке, связанных с HTTP.
То есть с HTTP вы должны постоянно запрашивать обновления (и получать ответ), что очень ресурсоемко: клиент устанавливает соединение, запрашивает обновление, получает ответ от сервера, а затем закрывает соединение. Представьте, что этот процесс повторяется бесконечно тысячами одновременно работающих пользователей — это невероятно обременительно для масштабируемого сервера.
Именно эти проблемы в конечном итоге побудили разработчиков Майкла Картера и Яна Хиксона разработать WebSockets — по сути, тонкий транспортный уровень, построенный поверх стека TCP/IP. Идея состояла в том, чтобы предоставить веб-приложениям то, что по сути является коммуникационным уровнем TCP, максимально приближенным к исходному, исключив несколько абстракций, чтобы устранить определенные сложности, связанные с безопасностью, и другие проблемы.
Ранее мы писали о концептуальном глубоком погружении в WebSockets, а также освещали эволюцию HTTP и сравнивали HTTP/2 и HTTP/3, поэтому не будем возвращаться к этому здесь.
Вместо этого в этом посте будут рассмотрены некоторые методы, используемые для обхода ограничений парадигмы HTTP — запроса/ответа в приложениях реального времени, некоторые проблемы этой парадигмы и то, как WebSockets может помочь их преодолеть.
HTTP
HTTP — это, по сути, протокол запроса/ответа в клиент-серверной модели и основной режим связи в веб. Первоначальная версия, предложенная Тимом Бернерсом-Ли в 1989 году, была очень ограниченной и ее быстро изменили для поддержки более широкой функциональности браузера и сервера.
Эти модификации были в конечном итоге задокументированы рабочей группой HTTP в 1996 году как HTTP/1.0 (RFC 1945), хотя HTTP/1.0 не считается формальной спецификацией или стандартом.
HTTP/1.1
HTTP/1.1 является наиболее широко поддерживаемой версией в веб-браузерах и на серверах, и его появление стало большим шагом вперед, потому что HTTP/1.1 позволил сделать некоторые довольно важные оптимизации и улучшения, от постоянных и конвейерных соединений до новых полей заголовка запроса/ответа. Главными из них являются два заголовка, которые служат основой для многих улучшений, помогающих сделать Интернет более динамичным в реальном времени.
Заголовок Keep-Alive: используется для установки постоянной связи между хостами. Это означает, что соединение может быть повторно использовано для более чем одного запроса, что заметно снижает задержку запроса, поскольку клиенту не нужно повторно согласовывать соединение TCP 3-Way-Handshake после отправки первого запроса. Еще один положительный эффект заключается в том, что в целом соединение со временем становится быстрее из-за механизма медленного запуска TCP. До HTTP/1.1 вам приходилось открывать новое соединение для каждой пары запрос/ответ.
Заголовок Upgrade: используется для обновления соединения до режима расширенного протокола (например, WebSockets).
HTTP-опрос
HTTP-опрос представляет собой шаг вперед по сравнению с классическим механизмом запроса/ответа — хотя, существуют различные версии опроса, но только длинный опрос каким-либо образом применим к приложениям реального времени.
Например, короткий опрос HTTP используется таймером на основе AJAX, чтобы клиентские устройства отправляли запросы к серверу через фиксированные интервалы. Однако сервер по-прежнему будет немедленно отвечать на каждый запрос, либо предоставляя новые данные, либо отправляя «пустой» ответ, если новых данных нет, перед закрытием соединения. Так что для приложений реального времени это принесет не так много пользы, когда клиенту нужно знать о новых данных, как только они становятся доступными.
Именно это ограничение привело к развитию длинного опроса HTTP, который, по сути, представляет собой метод, предназначенный для имитации функции отправки данных на сервер.
Мы подробно рассмотрели длинный опрос HTTP здесь, но, по сути, длинный опрос — это метод, при котором сервер предпочитает держать клиентское соединение открытым как можно дольше (обычно до 20 секунд), доставляя ответ только после того, как данные становится доступным или истек порог тайм-аута.
Основным преимуществом длинного опроса является то, что новая информация теоретически отправляется клиенту, как только она становится доступной. Обратной стороной, однако, являются дополнительные расходы, связанные с обработкой HTTP-запросов, которые могут создать множество проблем при большом масштабе.
Потоковая передача HTTP
Потоковая передача HTTP — это метод передачи данных в стиле push, который позволяет веб-серверу непрерывно отправлять данные клиенту по одному HTTP-соединению, которое остается открытым бесконечно. По сути, клиент делает HTTP-запрос, а сервер отправляет ответ неопределенной длины.
Однако, хотя потоковая передача HTTP является производительной, простой в использовании и может быть альтернативой WebSockets, у нее есть ограничения. Основная проблема с точки зрения реального времени заключается в том, что посредник может прервать соединение — будь то из-за тайм-аута или просто потому, что он обслуживает несколько запросов в «циклическом стиле», поэтому не всегда можно гарантировать работу в реальном времени.
HTTP/2.0
HTTP/2.0 произошел от экспериментального протокола — SPDY — который был первоначально анонсирован Google в 2009 году. К 2015 году рабочая группа HTTP опубликовала HTTP/2.0 в качестве предлагаемого стандарта, взяв за отправную точку спецификацию SPDY.
Мы рассмотрели HTTP/2.0 в деталях ранее, это было по существу обновление производительности предназначено для повышения скорости веб-коммуникаций. Основными достижениями в области связи в реальном времени были:
Мультиплексирование: вместо того, чтобы передавать данные в формате открытого текста, данные кодируются как двоичные и инкапсулируются внутри кадров, которые могут быть мультиплексированы по двунаправленным каналам, известным как потоки, по одному TCP-соединению. Это позволяет выполнять множество параллельных запросов /ответов одновременно.
Server push: Server push — это функция производительности, которая позволяет серверу отправлять ответы клиенту, до того, как клиент их запросит. Эта функция полезна, когда сервер знает, что клиенту нужны «отправленные» ответы для полной обработки исходного запроса.
Несмотря на эти и другие шаги вперед, взрывной рост интернет-трафика, вызванный массовым распространением мобильных устройств, привел к тому, что HTTP / 2.0 столкнулся с трудностями в обеспечении плавного и прозрачного просмотра веб-страниц — особенно в условиях постоянно растущих требований приложений реального времени и их пользователей.
Плюсы HTTP/2.0
Все браузеры поддерживают протокол HTTP/2 поверх HTTPS с установкой сертификата SSL.
HTTP/2 позволяет клиенту отправлять все запросы одновременно через одно TCP-соединение. Теоретически клиент должен быстрее получать данные.
TCP — это надежный и стабильный протокол соединения.
Минусы HTTP/2.0
Параллельные запросы могут увеличить нагрузку на серверы. Серверы HTTP/2 могут получать запросы большими партиями, что может привести к истечению времени ожидания запросов. Проблема скачка нагрузки на сервер может быть решена путем установки балансировщика нагрузки или прокси-сервера, который может ограничивать запросы.
Серверная поддержка приоритезации HTTP/2 еще не развита. Поддержка программного обеспечения все еще развивается. Некоторые сети CDN или балансировщики нагрузки могут некорректно поддерживать приоритизацию.
Функцию push в HTTP/2 бывает сложно реализовать правильно.
HTTP/2 имеет HTTP-блокировку заголовка строки, но блокировка на уровне TCP все еще может вызывать проблемы.
HTTP/3.0
HTTP/3.0 — это новая итерация HTTP, которая разрабатывается с 2018 года, и, хотя на момент написания (по состоянию на октябрь 2020 года) он все еще является черновиком стандарта, некоторые браузеры уже используют его.
Цель HTTP/3 — обеспечить быстрые, надежные и безопасные веб-соединения для всех форм устройств, устраняя проблемы HTTP/2 связанные с передачей данных. Для этого он использует другой сетевой протокол транспортного уровня, называемый QUIC, который работает по протоколу пользовательских дейтаграмм (UDP) вместо TCP, который использовался всеми предыдущими версиями HTTP.
Некоторые потенциальные проблемы с HTTP/3 уже начинают появляться. Например:
Разветвления транспортного уровня. Переход на HTTP/3 включает не только изменение уровня приложения, но и изменение нижележащего транспортного уровня. Следовательно, внедрение HTTP/3 немного сложнее по сравнению с его предшественником.
Проблемы надежности и целостности данных. UDP обычно подходит для приложений, в которых возможна потеря пакетов. Это потому, что UDP не гарантирует, что ваши пакеты будут доставлены по порядку. Фактически, это не гарантирует, что ваши пакеты вообще будут доставлены. Поэтому, если целостность данных важна для вашего варианта использования и вы используете HTTP/3, вам придется создать механизмы, обеспечивающие упорядочение сообщений и гарантированную доставку.
Плюсы HTTP/3.0
Внедрение нового (другого) транспортного протокола QUIC, работающего по UDP, означает уменьшение задержки как теоретически, так, пока и экспериментально.
Поскольку UDP не выполняет проверку и исправление ошибок в стеке протоколов, он подходит для случаев использования, когда они либо не требуются, либо выполняются в приложении. Это означает, что UDP избегает любых дополнительных расходов. UDP часто используется в приложениях, чувствительных ко времени, таких как системы реального времени, которые не могут позволить себе ждать повторной передачи пакетов и, следовательно, допускают потерю некоторых пакетов.
Минусы HTTP/3.0
Разветвления транспортного уровня. Переход на HTTP/3 включает не только изменение уровня приложения, но и изменение нижележащего транспортного уровня. Следовательно, внедрение HTTP/3 немного сложнее по сравнению с его предшественником.
Вопросы надежности. Приложения UDP, как правило, не обладают надежностью, необходимо учитывать, что будет определенная степень потери пакетов, переупорядочения, ошибок или дублирования. Приложения конечного пользователя должны обеспечить необходимое подтверждение , например подтверждение в реальном времени что сообщение было получено.
HTTP/3 еще не полностью стандартизирован.
WebSockets
WebSockets позволяет как серверу, так и клиенту отправлять сообщения в любое время без какого-либо отношения к предыдущему запросу. Одним из заметных преимуществ использования WebSockets является то, что почти каждый браузер их поддерживает.
WebSocket решает несколько проблем с HTTP:
Двунаправленный протокол — любой клиент / сервер может отправить сообщение другой стороне (в HTTP запрос всегда инициируется клиентом, а ответ обрабатывается сервером, что делает HTTP однонаправленным протоколом)
Полнодуплексная связь — клиент и сервер могут одновременно разговаривать друг с другом независимо.
Единое TCP-соединение — клиент и сервер обмениваются данными через одно и то же TCP-соединение (постоянное соединение) на протяжении всего жизненного цикла соединения WebSocket.
Плюсы WebSocket
WebSocket — это протокол, управляемый событиями, что означает, что вы можете использовать его для общения в реальном времени. В отличие от HTTP, где вам нужно постоянно запрашивать обновления, с веб-сокетами изменения отправляются немедленно, как только они станут доступны.
WebSockets поддерживает единое постоянное соединение открытым, устраняя проблемы с задержкой, возникающие при использовании методов HTTP-запросов / ответов.
WebSockets обычно не используют XMLHttpRequest, и поэтому заголовки не отправляются каждый раз, когда нам нужно получить дополнительную информацию с сервера. Это, в свою очередь, снижает объем данных, отправляемых на сервер.
Минусы WebSocket
WebSockets не восстанавливаются автоматически при разрыве соединения — это то, что вам нужно реализовать самостоятельно, и это одна из причин, по которым существует множество клиентских библиотек.
Браузеры старше 2011 года могут не поддерживать WebSocket, но это становится все менее актуальным.
Почему протокол WebSocket — лучший выбор
Как правило, WebSockets будет лучшим выбором в контексте постоянного взаимодействия в реальном времени.
Методы на основе HTTP, как правило, намного более ресурсоемки на серверах, тогда как WebSockets занимают чрезвычайно мало места. Между тем, такие подходы, как длинный опрос, также требуют большого количества переходов между серверами и устройствами, и эти шлюзы часто имеют разные представления о том, как долго типичное соединение может оставаться открытым. Если соединение остается открытым слишком долго, что-то может убить его, возможно, даже когда соединение делало что-то важное.
Почему вы должны использовать WebSockets:
Веб-сокеты управляются событиями (в отличие от HTTP). Можно утверждать, что управляемость событиями является предпосылкой для приложения реального времени.
Полнодуплексный асинхронный обмен сообщениями. Другими словами, и клиент, и сервер могут передавать друг другу сообщения независимо.
Хорошая модель безопасности.
Ably, WebSockets и HTTP
Большинство Ably’s client library используют WebSocket для установления соединения в реальном времени с Ably, а затем используют простой HTTP-запрос для всех других операций REST, включая аутентификацию.
Однако пакеты клиентской библиотеки SDK, подобно нашей Javascript browser library, предназначены для выбора наилучшего доступного транспорта в зависимости от браузера и подключения. Поддерживая дополнительные протоколы связи с возможностью возврата к наименьшему общему знаменателю, Ably гарантирует, что практически каждый используемый сегодня браузер сможет установить соединение с Ably в реальном времени. В настоящее время, следующие протоколы связи поддерживаются Javascript browser library в порядке от лучшего к худшему:
WebSockets (поддерживается 98% браузеров по всему миру по состоянию на октябрь 2020 г.)
потоковая передача XHR
опрос XHR
опрос JSONP
Однако при реализации поддержки WebSockets с помощью методов на основе HTTP, таких как длинный опрос в качестве запасного варианта, требуется много усилий. Например, помимо деталей реализации клиента и сервера, вам также необходимо встроить поддержку других протоколов передачи, чтобы обеспечить надежную поддержку для различных клиентских сред, а также более широкие проблемы, такие как аутентификация и авторизация, гарантированная доставка сообщений, надежный порядок сообщений, хранение сообщений и многое другое.
Автор: Martin Fietkiewicz
Источник: ably.com
Редакция: Команда webformyself.
Читайте нас в Telegram, VK, Яндекс.Дзен