Блог компании PENXY / Azure Service Bus: неклассическое применение

в 15:37, , рубрики: azure, PENXY, Pubsub, Service Bus

Azure Service Bus как Messaging System для «массовых» клиент-серверных приложений

imageПриветствую вас!

Перед тем, как расказать вам интересненького, позвольте для начала представиться. Мы — молодая компания, занимающаяся дистанционным обучением. В этом блоге мы будем делиться с вами нашими интересными находками, техническими хитростями и прочими вещами, которые, как мы считаем, должны быть достоянием сообщества.
Дальше будет несколько слов о нас, и, собственно, вынесенный в заглавие рассказ о неочевидном применении Azure Service Bus. <a rel="nofollow" name="habracut">

Кто вы такие и что вы делаете?

Когда то, совсем недавно образование касалось компьютера только на информатике, да и то не везде. С тех пор многое изменилось (у нас в стране – в меньшей степени, в Штатах, к примеру, – в большей): многие уже сейчас получают образование онлайн. Естественно, в новой области как грибы стали появляться програмные решения. И, как обычно это бывает, большая часть этих самописных систем предоставляла очень сильно ограниченый функционал. Такие системы используются до сих пор в разнообразных учебных заведениях. Потом в эту нишу стали подтягиваться крупные компании с серьезными решениями (например, Adobe), но вердикт учителей, которым приходится это использовать, звучит неутешительно. Им неудобно пользоваться существующими решениями.
Наша компания на данном этапе разрабатывает одноименный продукт (PENXY), являющийся комплексной системой для онлайн обучения, причем как синхронного (похожего на вебинары), так и асинхронного (похожего на форумы, учебники, тестовые задания). Основной особенностью нашего подхода является то, что мы постоянно обсуждаем наши решения и идеи с преподавателями, стараясь максимизировать для них удобство использования системы. Ведь согласитесь, что действительно качественное онлайн образование – это здорово!

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

Хватит слов, давайте к делу!

Наша система построена по клиент-серверной архитектуре с использованием облачных технологий. Соответственно, по ходу проектирования и разработки мы сталкивались с различными интересными проблемами и не менее интересными (а порой и довольно экстравагантными) решениями. Частью этих наблюдений мы бы хотели поделиться с хабром.

Удивительным образом на хабре мало статей про Windows Azure (ну, за исключением общих обзоров и ежемесячных рассылок). Еще меньше затронута часть Azure под названием Service Bus. В общих чертах о том, что это такое, и зачем это нужно, можно прочитать в статьях Дэвида Чеппела. Например, на хабре, а именно тут и тут есть перевод обзорной статьи по Azure в 2 частях, в которой, в частности, описано применение Service Bus при построении корпоративных систем. Из нее может сложиться ощущение, что эта технология нужна лишь для того, чтобы связывать вместе части бизнес-решения расположенные в облаке и на on-premise.

Несмотря на то, что микрософтовский «независимый евангилист» Чеппел в своей статье рассматривает только указанное применение данной технологии, сейчас эта часть Azure имеет достаточно большой и удобный функционал Message Broker-a. С момента написания статьи произошло два изменения: Microsoft допилила функционал и сменила ценовую политику. Про функционал чуть позже, а сейчас ненадолго обратимся к ценам. Вообще, ценовая политика в отношении Service Bus, которую сначала проводила Майкрософт, очень сильно ограничивала область применения Service Bus: оплата производилась за каждое подключение к шине. В декабре ценовая политика была изменена, и теперь в Service Bus оплачивается каждая транзакция. Оплаты подключений нет, однако их количество ограничено. По сути, Service Bus теперь стоит столько же, сколько и Azure Storage. Более подробно о новом ценообразовании Service Bus можно прочитать на оффициальном сайте.

В результате спектр применений Service Bus существенно расширился. Но прежде чем перейти к описанию возможных применений этой технологии, я расскажу собственно о ее устройстве.

Ура, картинки!

Блог компании PENXY / Azure Service Bus: неклассическое применение

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

Основные свойства Service Bus:

  • Безопасно открывает доступ к внешним веб сервисам на базе WCF, которые закрыты брандмауэрами и NAT-роутерами, причем делает это без необходимости открывать какие-либо входящие порты или еще как либо перенастраивать брандмауэр или роутер.
  • Обеспечивает безопасные входящие соединения от устройств вне брандмауэра.
  • Предоставляет единое пространство имен, которое совершенно отвязано от географического положения. Это означает, что такой информации не содержится в имени сервиса.
  • Предоставляет механизмы публикации и поиска endpoint-ов в пространстве имен.
  • Предоставляет возможности пересылки сообщений. Поддерживается односторонний обмен сообщениями, обмен сообщениями по модели запрос/ответ и p2p взаимодействия.
  • Предоставляет функции брокера сообщений, в частности дает возможность асинхронного обмена сообщениями (отправитель и получатель сообщения не обязаны быть одновременно онлайн). Инфраструктура устроена таким образом, что сообщения надежно хранятся до тех пор, пока получатель не будет готов их принять.
  • Создает и обслуживает endpoint-ы сервисов, также допускает туннелирование между двумя endpoint-ами, позволяя двунаправленную передачу данных.

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

Блог компании PENXY / Azure Service Bus: неклассическое применение

Все клиенты подключены к нашему серверу в облаке, один из клиентов отправляет сообщение, часть из клиентов получает сообщение (т.е. мы предполагаем разделение по комнатам). Но если бы все было так просто! Я сейчас не говорю даже про постоянные двунаправленные соединения, которые нужно поддерживать (чтобы клиентам не приходилось постоянно запрашивать у сервера, не пришло ли новых сообщений, хотя, конечно же, и такой подход тоже годится). Все дело в том, что для каждой роли в облаке создано несколько инстансов. С учетом того, что мы не контролируем то, к какому конкретно инстансу подключен каждый клиент, возникает необходимость передачи сообщений между инстансами в той или иной форме. Более того, с учетом того, что в одной комнате народу существенно больше, чем инстансов, автоматически получается, что на всех инстансах есть клиенты из данной комнаты. Т.е. получается, что каждый инстанс передает сообщения всем остальным инстансам. Это вполне естественный подход, более того, Майкрософт в своих лабах предлагает именно его. В результате получаем следующую картинку:

Блог компании PENXY / Azure Service Bus: неклассическое применение

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

Блог компании PENXY / Azure Service Bus: неклассическое применение

Альтернативой является вообще использование Storage в качестве транзитной сущности между инстансами, но это не очень важно в рамках данной статьи. Вообще говоря, получилась достаточно сложная схема, которая предполагает использование Storage, несколько инстансов роли и не самое очевидное взаимодействие. Оказывается, нашу задачу в некоторых случаях можно решить существенно проще. Будем считать, что комнат у нас в чате менее 100 тысяч, в каждой комнате не более 100 человек, а комнаты заданы статично или редко меняются. Такие ограничения озвучены не случайно. Т.к. я планирую использовать в данном примере Service Bus и одно пространство имен, то и ограничения взяты соответственно.

В новой схеме каждая комната в чате — это топик (специальная сущность, реализующая public subscribe подход) внутри Service Bus. Каждый клиент подключается напрямую к Service Bus, посылает сообщения в топик и получает сообщения по подписке. Выглядит это все примерно вот так:

Блог компании PENXY / Azure Service Bus: неклассическое применение

А что с безопасностью?

Важно понимать, что если использовать простые очереди Service Bus или одну подписку на всех клиентов, то каждое сообщение в чате будет доставлено первому подсуетившемуся клиенту и все. Именно поэтому мы используем функционал топиков, а не очередей, и создаем по подписке на каждого клиента. К сожалению, этот подход тоже имеет свои минусы. Дело в том, что у Service Bus пока нет возможности получить security token, который позволил бы, к примеру, только отправлять и получать сообщения, но не позволил бы создавать и удалять топики. Т.е. если вы разрешаете клиенту работу с Service Bus, то он получает полный доступ со всеми вытекающими из этого рисками безопасности. Тем не менее, такое решение применяется и на практике, ведь при таком подходе вам не нужны никакие роли. В этом случае полномочия в том или ином виде либо хранятся на клиенте в зашифрованном виде, например в keychain в маках, либо их должен выдавать сервер в момент подключения клиента, естественно это предполагает безопасное соединение и работающую веброль. Вообще, даже если мы решим, что нам нужно обеспечить полную безопасность и будем использовать, к примеру, веброль для проксирования запросов к Service Bus (для того, чтобы спрятать от клиента этот токен), решение окажется все равно проще, ибо многие вопросы, например, управление комнатами, решаются при таком подходе существенно проще непосредственно возможностями Service Bus.
Отдельно стоит отметить, что клиенту не обязательно быть .Net-based для того, чтобы взаимодействовать с ServiceBus. Вот, к примеру, ссылка на эту тему.

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

Напоследок

Ясно, что, чтобы получить этот результат, вовсе не обязательно брать готовое решение, встроенное в Azure. Есть множество других способов добиться таких же (на первый взгляд) результатов. Вопрос как обычно заключается в специфике ваших задач и потребностей. Из возможных претендентов можно выделить:

Low-lattency / High Throughput / in-RAM:

  • NoSQL хранилища/кэши с функционалом publish/subscribe — например redis (да-да, юниксовое хранилище вполне живет в Azure, правда со scaling-ом пока проблемы)
  • Реализации паттернов Complex Event Processing — например микрософтовский StreamInsight, умеющий не только перебрасывать данные но и производить подробную обработку сигналов в реал-тайме. (и таки да, это тоже скоро появиться в Azure)
  • ZeroMQ и прочие Messaging Queue Systems

Guaranted Delivery / Redundant:

  • MSMQ
  • Всевозможные реализации паттерна Enterprise Service Bus (кроме рассмотренной азурной), работающие по принципу «отправил-забыл, не потеряется»

Если, хабру будет интересно, мы с удовольствием расскажем об опыте работы с подобными решениями и о тех подводных камнях, с которыми мы на данный момент уже успели познакомиться.
Автор:

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js