В этом посте я сравниваю два облачных сервиса pubsub: Azure Web PubSub и Ably, чтобы определить, какой из них обеспечивает лучший опыт разработки. Контекстом будет многопользовательское приложение для рисования пиксельной графики, которое я создал с помощью обоих сервисов.

  • Насколько легко использовать их SDK/API?
  • Сколько кода вам нужно написать, чтобы добавить возможности реального времени в ваше приложение?

Это не пошаговая инструкция по сборке всего приложения, я выделю некоторые ключевые особенности и отличия.

TLDR: рисуйте на живом холсте или просмотрите исходный код в репозитории GitHub, который включает CodeTours, чтобы помочь вам в решении.

Обмен сообщениями в реальном времени захватывает мир. Наши приложения для доставки еды показывают нам, что наша еда находится всего в 5 минутах ходьбы. Мы используем чат-приложения каждый день для работы и личного пользования. Мы получаем последние новости о спорте, акциях и новостях о знаменитостях на наши мобильные устройства и совместно работаем над цифровыми документами.

Как я упоминал в своей недавней статье о pubsub с C#.NET, использование pubsub в многопользовательских приложениях реального времени дает множество преимуществ. Количество облачных служб обмена сообщениями, включающих pubsub на стороне клиента, значительно выросло, и разработчикам может быть сложно принять решение, какую из них использовать. Доступные сервисы построены с использованием таких протоколов, как WebSockets: некоторые сервисы предлагают собственный API WebSocket напрямую, в то время как другие создали над ним абстракции, упрощающие его использование.

Давайте посмотрим на технологии, используемые в этом приложении, и остановимся на облачных поставщиках WebSockets.

Стек технологий

Я создал две версии приложения для совместного рисования. Обе версии используют следующие компоненты:

  • p5js: библиотека творческого кодирования, используемая для холста для рисования.
  • Функции Azure: служба бессерверных вычислений от Microsoft Azure, используемая для конечной точки аутентификации, и функция для изменения цветовой палитры.
  • Статические веб-приложения Azure: служба Azure для размещения статического веб-приложения.

Бессерверные веб-сокеты

В одной версии приложения для рисования используется Ably, в другой — Azure Web PubSub. Оба являются облачными службами pubsub (или бессерверными поставщиками WebSocket), используемыми для связи в реальном времени. Вот обзор некоторых функций, которые они предлагают.

¹ Надежный подпротокол Web PubSub все еще находится в стадии предварительной версии.
² Возможность использовать наилучший доступный транспорт в зависимости от возможностей клиента.

Связь между клиентами и облачной службой обмена сообщениями показана на этой диаграмме:

Как я сравниваю облачные сервисы pubsub

Я сравниваю эти два сервиса по следующим критериям:

  • Создание облачного ресурса
  • Аутентификация
  • Создание подключения на стороне клиента
  • Присутствие
  • Публикация сообщений
  • Подписка на сообщения

Именование

Прежде чем я начну сравнивать опыт разработчиков, давайте сначала взглянем на наименования, поскольку оба облачных сервиса иногда используют разную терминологию для определенных понятий.

Для получения более подробной информации см. разделы Внутреннее устройство Web PubSub Service и Ably Key Concepts.

Создание облачного ресурса

Прежде чем мы сможем что-то сделать с облачным обменом сообщениями, нам нужно создать соответствующие ресурсы.

умело

Для Ably первое, что нужно сделать, — это создать новое приложение Ably и ключ API. Если вы только что зарегистрировались, для вас уже создано новое приложение по умолчанию и корневой ключ API. Я предлагаю вам создать специальное приложение Ably для каждого приложения, которое вы создаете.

То же самое касается ключа API. Ключ корневого API по умолчанию имеет все возможности, которые предлагает Ably, и, вероятно, имеет слишком много прав. Для этого приложения вам потребуются только возможности Опубликовать, Подписаться и Присутствие. Ключ API требуется при использовании Ably SDK для аутентификации.

Создать приложение Ably и ключ API можно с помощью:

Веб-пабSub

Для службы Web PubSub необходимо создать новый ресурс службы Web PubSub в Azure. Вам требуется Подписка Azure. При создании облачного ресурса необходимо указать группу ресурсов и регион для развертывания службы.

После создания экземпляра службы вы найдете строки подключения в колонке Keys на портале. Одна из этих строк подключения требуется при использовании серверного Web PubSub SDK для проверки подлинности.

Создать ресурс Azure можно с помощью:

Различия в создании ресурсов

Для ресурса Azure необходимо определить регион, в котором будет развернут ресурс Web PubSub. Для Ably вам не нужно выбирать регион, он по умолчанию мультирегиональный (размещен на AWS). Когда клиентское соединение установлено, клиент Ably выберет регион с наименьшей задержкой.

Для Ably вам необходимо создать ключ API с необходимыми возможностями, если только вы не используете корневой ключ со всеми возможностями. Для Web PubSub существуют строки подключения (первичные и вторичные) и генератор URL-адресов клиентов, предназначенный только для целей тестирования и проверки.

Аутентификация

Чтобы клиент мог подключиться к облачной службе, ему требуется токен клиентского доступа. И Web PubSub, и Ably предоставляют SDK для генерации этих токенов на стороне сервера, поскольку не рекомендуется использовать эти токены в коде на стороне клиента. Для создания токенов пакетам SDK требуется строка подключения или ключ API для аутентификации в облачной службе.

умело

Для Ably функция Azure написана на C#, которая использует пакет .NET Ably.io NuGet для создания токена клиентского доступа:

См. GitHub для полной реализации.

Функция CreateTokenRequest зависит от объекта Ably IRestClient через внедрение конструктора. Зависимость настраивается в классе StartUp:

См. GitHub для полной реализации.

Ключ Ably API, упомянутый в разделе Создание облачного ресурса, помещается в параметры приложения приложения-функции Azure, поэтому его можно получить как переменную среды и использовать, когда экземпляр AblyRest клиента создано.

Azure Web PubSub

Для Azure Web PubSub создается аналогичная CreateTokenRequest Функция Azure, использующая пакет NuGet Azure.Messaging.WebPubSub.

См. GitHub для полной реализации.

Ключ строки подключения Web PubSub, упомянутый в разделе Создание облачного ресурса, помещается в параметры приложения приложения-функции Azure, извлекается как переменная среды и используется при создании экземпляра WebPubSubServiceClient.

Различия в аутентификации

Специфическая функция Ably зависит от клиента AblyRest, для которого требуется только ключ API Ably. Ключ API имеет настроенные возможности для публикации, подписки и управления присутствием для канала. Это означает, что если для разных ролей требуется несколько разных прав доступа, необходимо создать несколько ключей API.

Специальная функция Web PubSub требует дополнительных параметров для создания токена клиента:

  • Строка подключения службы.
  • Имя концентратора
  • Название группы*
  • Идентификатор клиента*
  • Роли для выхода и вступления в группу*

* Они необходимы, поскольку для подключения клиента используется определенный подпротокол. См. раздел Создание подключения на стороне клиента.

Строка подключения Web PubSub имеет все права на службу. При создании токена клиентского доступа определяется групповой доступ.

Хотя результат более или менее одинаков (маркер доступа клиента), уровень детализации, необходимый для создания подключения, отличается.

Поскольку WebPubSubServiceClient требует имени концентратора рядом со строкой подключения, я решил не использовать внедрение зависимостей для клиента службы. В противном случае мне также пришлось поместить имя концентратора в переменную среды. Я считаю, что имя концентратора должно быть действительно динамическим, поэтому я предпочитаю, чтобы оно не присутствовало в конфигурации или внутреннем коде.

Создание подключения на стороне клиента

Пользователю (с клиентским устройством) необходимо установить соединение с облачным сервисом. Код на стороне клиента вызовет функцию Azure CreateTokenRequest, показанную ранее, которая вернет маркер доступа клиента для установки подключения на основе WebSocket.

умело

У Ably есть клиентский SDK для управления подключениями и обменом сообщениями вместо использования собственного API WebSockets. Создается экземпляр клиента Ably.Realtime, который использует конечную точку CreateTokenRequest для получения маркера доступа клиента, содержащего идентификатор пользователя.

После подключения клиента ably можно получить channel:

Обратите внимание, что параметр rewind используется для получения последних двух минут сообщений. Это возможно, потому что сообщения сохраняются Ably.

Azure Web PubSub

Azure Web PubSub использует API WebSocket напрямую, указав URL-адрес с маркером доступа клиента и подпротокол:

См. GitHub для полной реализации.

Различия в подключении на стороне клиента

Для Ably клиентская библиотека JavaScript используется для создания соединения на основе WebSocket и взаимодействия с облачным сервисом. Преимущество использования этой библиотеки по сравнению с родным API WebSocket заключается в том, что за вас позаботятся многие стандартные коды WebSocket и сложные для реализации концепции, такие как надежное управление соединениями и порядок сообщений.

Для Web PubSub при создании соединения указывается json.webpubsub.azure.v1 подпротокол WebSocket. Это необходимо для выполнения pubsub без необходимости использования обработчиков событий, которые отправляют сообщения на вышестоящий сервер. Недостатком использования этого подпротокола является то, что пользовательские события могут поддерживаться только с помощью обработчиков событий. В этом приложении я не использовал никаких интеграций/обработчиков событий для уменьшения сложности.

Присутствие

Когда пользователь посещает веб-приложение и нажимает кнопку Подключиться, он подключается к службе обмена сообщениями, и его (случайно сгенерированный) идентификатор клиента добавляется в коллекцию users в клиентском коде. Рядом с кнопкой отображается общее количество подключенных пользователей (фактически клиентских устройств):

Как узнать, какие (или сколько) клиенты подключены к каналу? Это понятие называется присутствие.

умело

В Ably присутствие — это встроенная функция, доступная через клиентские SDK.

Следующие четыре действия выполняются, когда пользователь установил соединение с Ably:

  1. Подпишитесь на сообщения enter о присутствии.
  2. Подпишитесь на сообщения о присутствии оставить.
  3. Получить присутствие канала.
  4. Введите их собственное присутствие.

Подписка на войти и оставить сообщения о присутствии, опубликованные другими клиентами, осуществляется через объект channel.presence:

Полное присутствие канала можно получить следующим образом:

Получение общего присутствия канала очень полезно, поскольку вам не нужно самостоятельно хранить подключенных пользователей. Как только клиент присоединился к каналу, он может получить сведения о присутствии и узнать, какие пользователи присутствуют на том же канале.

Клиент может объявить о своем присутствии на канале следующим образом:

Обратите внимание, что вы можете отправить полезные данные JSON при вводе (или обновлении) сведений о присутствии. Это идеально подходит для хранения данных, специфичных для клиента. В данном случае это цвет их пиксельного курсора.

См. GitHub для полной реализации присутствия пользователя.

Azure Web PubSub

Хотя Web PubSub имеет концепцию Группы и позволяет добавлять/удалять пользователей, он не позволяет получать информацию о пользователе из Группы. Таким образом, в Web PubSub нет оповещения о присутствии.

После установки подключения к службе Web PubSub выполняются следующие шаги:

  1. Отправьте сообщение joinGroup, чтобы пользователь стал частью этой группы и мог отправлять и получать групповые сообщения.
  2. Добавьте информацию о пользователе в коллекцию users (чтобы идентифицировать пользователя на стороне клиента).
  3. Отправьте сообщение sendToGroup, чтобы передать информацию о пользователе остальным членам группы.

См. GitHub для полной реализации.

Однако одна часть еще не учтена. Допустим, есть два клиента, A и B, которые последовательно подключаются (сначала A, затем B) к одному концентратору и группе. Когда B подключается к концентратору, B публикует сообщение sendToGroup, которое получает A, чтобы сообщить, что B присоединился. Но B понятия не имеет, что A также подключен, поскольку B подключился к хабу позже, чем A.

Единственный способ, с помощью которого B узнает об A, заключается в том, что A также отправляет сообщение sendToGroup. Решение, которое я выбрал, заключалось в том, чтобы всегда включать идентификатор клиента и цвет пиксельного курсора при публикации hoverPositionMessage (пользователь перемещает указатель мыши по пиксельной канве):

См. GitHub для полной реализации.

Мне не очень нравится такой подход, так как полезная нагрузка немного раздувается избыточной информацией. В идеале я бы отправил сюда только координаты x и y.

Различия в наличии

Разница между Ably и Azure Web PubSub значительна, когда речь идет о присутствии пользователя. Было бы здорово, если бы Web PubSub предлагал способ составления списка пользователей в группе. В настоящее время для получения той же функциональности, которую предлагает Ably, требуются некоторые обходные пути. С другой стороны, групповая концепция Web PubSub не имеет эквивалента в Ably. Можно сказать, что и концентраторы, и группы сопоставляются с каналами в Ably. Поэтому, если вам требуется несколько групп, вы можете использовать несколько каналов в Ably.

Публикация сообщений

Приложение публикует сообщения, когда:

  1. Мышь пользователя зависает над холстом.
  2. Пользователь щелкает пиксель на холсте.
  3. Пользователь вводит клавишу «r», чтобы сбросить холст.
  4. Пользователь выбирает цветовую палитру.

Сценарии 1–3 используют публикацию на стороне клиента. Сценарий 4 использует публикацию на стороне сервера (из функции Azure). Сценарий 4 также можно было бы реализовать с помощью публикации на стороне клиента, но я хотел использовать пакет SDK для .NET, чтобы увидеть, чем он отличается от JavaScript и какие другие варианты существуют при использовании кода на стороне сервера.

Публикация на стороне клиента

Давайте рассмотрим функцию mouseClicked в качестве примера публикации на стороне клиента.

умело

Для Ably метод publish используется для объекта channel. Метод требует имя события и полезную нагрузку.

См. GitHub для полной реализации.

Azure Web PubSub

Для Web PubSub метод send используется для объекта WebSocket. Метод принимает строку JSON и требует type, groupName и полезных данных.

См. GitHub для полной реализации.

Чтобы различать сообщения, я добавил в полезную нагрузку поле messageType. Аргумент noEcho является необязательным, но поскольку я не хочу, чтобы сообщение возвращалось пользователю, для него установлено значение true.

Различия в публикации на стороне клиента

Код Azure Web PubSub немного более подробный, поскольку используются группы. Однако использование групп требуется, поскольку используется подпротокол json.webpubsub.azure.v1, потому что мне не нужно было отправлять сообщения на вышестоящий сервер перед отправкой их клиентам. В идеале я хочу использовать настраиваемые события с использованием этого подпротокола без необходимости прохождения через вышестоящий сервер. Это то, что Ably делает по умолчанию, используя имя события в качестве первого аргумента.

noEcho можно настроить отдельно для каждого метода send с помощью Web PubSub. Хотя это очень гибко, мне интересно, сколько существует вариантов использования, требующих такой гибкости. Для Ably параметр echoMessages устанавливается при создании клиента Ably.Realtime и применяется ко всем методам publish.

Публикация на стороне сервера

Функция ChangeColorPalette Azure выбирает цветовую палитру на основе идентификатора палитры в маршруте и публикует сообщение в облачной службе.

умело

Для Ably публикация выполняется с помощью клиента AblyRest, который внедряется через конструктор и назначается параметру _ablyClient:

См. GitHub для полной реализации.

Канал получается по имени, и для этого канала вызывается метод PublishAsync, который принимает имя события (цветовая палитра) и полезную нагрузку, содержащую массивы paletteId и colors.

Azure Web PubSub

Для Web PubSub используется выходная привязка WebPubSub:

См. GitHub для полной реализации.

В целом мне очень нравятся привязки ввода и вывода в Функциях Azure, поскольку они предлагают быстрый способ перемещения данных в функцию и из нее без написания большого количества кода в теле функции. Однако привязка WebPubSub по-прежнему требует нескольких строк кода, так как полезная нагрузка должна быть отформатирована, должен быть создан объект WebPubSubAction, и его нужно добавить в файл IAsyncCollector.

Альтернативой может быть использование объекта WebPubSubServiceClient с методом SendToGroup в теле функции вместо выходной привязки. Это не будет сильно отличаться в отношении требуемых строк кода.

Различия в публикации на стороне сервера

На стороне сервера объем кода, необходимый для публикации сообщения, одинаков между Ably и Azure Web PubSub. Я ожидал, что при использовании выходной привязки для Web PubSub будет меньше кода, но это не так. Рассматривая шаги, необходимые для публикации сообщения, я нахожу API Ably немного более кратким и читабельным.

Подписка на сообщения

Клиенты подписываются на следующие сообщения:

  • hoverPositionMessage: при перемещении мыши по холсту.
  • clickPositionMessage: при щелчке мышью на холсте.
  • changeColorPaletteMessage: при изменении цветовой палитры.
  • resetMessage: при сбросе холста.

умело

Для Ably подписка на определенные сообщения выглядит так:

См. GitHub для полной реализации.

Кроме того, клиент может подписаться на события присутствия, когда пользователь присоединяется к каналу или покидает его:

См. GitHub для полной реализации.

Azure Web PubSub

Для Azure Web PubSub, поскольку он использует собственный API WebSocket, используется событие onmessage, которое фиксирует все виды событий. Разработчик должен отфильтровать точный тип, и поскольку я добавил в полезную нагрузку отдельное поле messageType, оно используется для идентификации точного сообщения.

См. GitHub для полной реализации.

Различия в подписке

Самая большая разница заключается в событиях присутствия, которые поддерживаются Ably, но не поддерживаются Azure Web PubSub. Кроме того, Ably поддерживает имена событий, что делает подписку на определенные события очень удобной. Для Web PubSub отсутствие подписки на определенные события приводит к большому оператору switch внутри обработчика onmessage. Azure Web PubSub поддерживает настраиваемые события, но их необходимо обрабатывать с помощью обработчиков событий и отправлять на вышестоящий сервер, что усложняет работу.

Краткое содержание

И Azure Web PubSub, и Ably предлагают аналогичный набор функций pubsub. Ably предоставляет некоторые дополнительные функции, не предлагаемые Web PubSub, такие как присутствие, история сообщений и выбор транспорта. Больше всего мне не хватало присутствия при создании приложения с помощью Web PubSub.

Я обнаружил, что клиентский API Ably легче разрабатывать, чем собственный API WebSockets. Использование клиентского SDK более высокого уровня для обмена сообщениями в реальном времени устраняет большую сложность и делает код более кратким. Я предпочитаю писать меньше кода и сосредотачиваться на (бизнес) сфере, поэтому я доволен использованием клиентских SDK, если они облегчают мою жизнь.

Возможность публиковать именованные события и подписываться на них (на стороне клиента) без необходимости обработки их через вышестоящий сервер и пользовательские обработчики событий — это большой плюс для меня.

Потенциальным отрицательным аспектом использования сторонней библиотеки может быть размер загружаемого клиентского приложения. Если вам нужно свести это к минимуму, то это будет аргументом в пользу выбора собственных веб-сокетов.

Я не коснулся надежной доставки сообщений, упорядочения сообщений и поддержки нескольких регионов по умолчанию. Ably SDK полностью позаботится об этом за вас, и вам не нужно самостоятельно управлять ackIDs, connectionIds и reconnectionTokens.

Я признаю, что я предвзят, поскольку я использовал Ably больше, чем собственный API WebSockets. Но посмотрите фрагменты кода в этом посте и решите сами.

Я призываю вас клонировать/форкнуть репозиторий GitHub и запустить приложение для совместного рисования пикселей самостоятельно (с помощью Ably или Web PubSub). Попробуйте добавить к нему некоторые дополнительные функции pubsub и дайте мне знать, каков ваш опыт.

дальнейшее чтение