Руководство по использованию протокола AMQP 1.0 в служебной шине и Центрах событий Azure

Улучшенный протокол очередей сообщений (AMQP) 1.0 — это стандартный протокол кадрирования и передачи, который обеспечивает асинхронную безопасную и надежную передачу сообщений между двумя сторонами. Это основной протокол, применяемый для обмена сообщениями служебной шины Azure и Центров событий Azure.

Протокол AMQP 1.0 — это результат совместной работы в разных отраслях, которая объединила таких производителей ПО промежуточного слоя, как корпорация Майкрософт и Red Hat, с большим количеством пользователей ПО промежуточного слоя для обмена сообщениями, например компанией JP Morgan Chase, представляющей собой индустрию финансовых услуг. На форуме OASIS по технической стандартизации официально утверждено, что спецификации протокола и расширения AMQP соответствуют международному стандарту ISO/IEC 19494:2014.

Цели

В этой статье кратко представлены основные понятия спецификации обмена сообщениями по протоколу AMQP 1.0, а также спецификации расширений, разработанные техническим комитетом OASIS по AMQP. Здесь также объясняется, как Служебная шина Azure реализует и использует эти спецификации.

Цель заключается в том, чтобы все разработчики, использующие любой имеющийся стек клиента AMQP 1.0 на любой платформе, могли взаимодействовать со служебной шиной Azure через протокол AMQP 1.0.

Распространенные стеки общего назначения AMQP 1.0, такие как Apache Qpid Proton или AMQP.NET Lite, реализуют все основные элементы протокола AMQP 1.0, такие как сеансы или ссылки. Для этих базовых элементов иногда в качестве оболочки используется API более высокого уровня. В Apache Proton предусмотрены два API: императивный API Messenger и реактивный API Reactor.

Далее предполагается, что управление подключениями, сеансами и связями AMQP, а также обработка передачи кадров и управление потоком осуществляются с помощью соответствующего стека (например, Apache Proton-C) и для этого не требуется особое внимание со стороны разработчиков приложений. Кроме того, абстрактно предполагается, что доступны несколько примитивных возможностей API, например возможность подключения и создания абстрактных объектов отправителя (sender) и получателя (receiver), которые затем приобретают форму операций send() и receive() соответственно.

Расширенные возможности служебной шины Azure, например просмотр сообщений или управление сеансами, описываются в контексте AMQP, а также как многоуровневая псевдореализация на базе этой предполагаемой абстракции API.

Что такое AMQP?

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

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

Протокол можно использовать для симметричного однорангового обмена данными и взаимодействия с брокерами сообщений, поддерживающими очереди и объекты публикаций и подписок, например со служебной шиной Azure. Его можно также использовать для взаимодействия с инфраструктурой обмена сообщениями, в которой шаблоны взаимодействия отличаются от обычных очередей, как в случае с Центрами событий Azure. При получении событий концентратор событий выполняет роль очереди, но когда события считываются из него, он действует скорее как служба последовательного хранения. Это отчасти напоминает ленточный накопитель. Клиент выбирает смещение в доступном потоке данных и получает все события, начиная с этого смещения до самого последнего доступного.

Протокол AMQP 1.0 предусматривает возможность расширения, то есть его возможности можно дополнить с помощью новых спецификаций. Три спецификации расширения, описанные в этом документе, иллюстрируют его. Для обмена данными по существующей инфраструктуре HTTPS/WebSockets настройка собственных TCP-портов AMQP может оказаться сложной. Спецификация привязки определяет способ наложения протокола AMQP поверх инфраструктуры WebSockets. Чтобы обеспечить взаимодействие с инфраструктурой обмена сообщениями в режиме "запрос — ответ" для управления или предоставления дополнительных функций, спецификация управления AMQP определяет основные примитивные возможности взаимодействия. Для интеграции модели федеративной авторизации спецификация AMQP безопасности на основе претензий определяет, как связывать и обновлять маркеры авторизации, связанные с ссылками.

Основные сценарии использования протокола AMQP

В этом разделе объясняется базовое использование AMQP 1.0 с Службой шины Azure, которое включает создание подключений, сеансов и связей, а также передачу сообщений в и из сущностей Службы шины, таких как очереди, темы и подписки.

Самый авторитетный источник сведений о принципах работы протокола AMQP — спецификация AMQP 1.0. Но эта спецификация представляет собой руководство по реализации, а не по использованию протокола. В этом разделе рассматриваются все термины, необходимые для описания использования протокола AMQP 1.0 в служебной шине. Более подробное введение в AMQP и более широкое обсуждение AMQP 1.0 вы можете найти в этом видеокурсе.

Подключения и сеансы

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

На схеме показаны сеансы и соединения между контейнерами.

Таким образом, сетевое подключение привязывается к контейнеру. Его инициирует контейнер в роли клиента. При этом устанавливается исходящее подключение TCP через сокет к контейнеру в роли получателя, который ожидает передачи данных и принимает входящие подключения TCP. Подтверждение подключения включает согласование версии протокола, объявление или согласование использования TLS/SSL и согласование проверки подлинности и авторизации в рамках подключения на основе SASL.

Для служебной шины Azure или Центров событий Azure обязательно использование TLS. Он поддерживает подключения через TCP-порт 5671, при этом сначала на подключение TCP накладывается TLS перед входом в фазу согласования протокола AMQP, а также подключения через TCP-порт 5672, когда сервер незамедлительно требует обязательного перехода подключения на TLS, используя модель, предписанную AMQP. Привязка AMQP WebSockets создает туннель через TCP-порт 443, что эквивалентно подключениям по протоколу AMQP 5671.

После настройки подключения и TLS в служебной шине применяется один из двух вариантов механизма SASL.

  • SASL PLAIN, как правило, используется для передачи имени пользователя и пароля на сервер. В Service Bus нет учетных записей, но есть именованные правила безопасности общего доступа, которые связаны с ключом и предоставляют права. Имя правила используется в качестве имени пользователя, а ключ (текст в кодировке Base64) — в качестве пароля. Права, связанные с выбранным правилом, определяют операции, разрешенные для подключения.
  • SASL ANONYMOUS используется для обхода авторизации SASL, когда клиент хочет использовать модель безопасности на основе утверждений (CBS), которая описана далее в этой статье. Используя этот вариант, подключение клиента можно установить анонимно на короткий период времени, в течение которого он может взаимодействовать только с конечной точкой CBS. При этом необходимо выполнить подтверждение CBS.

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

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

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

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

Сейчас в служебной шине Azure для каждого подключения используется только один сеанс. Максимальный размер кадра для Service Bus в категории Standard составляет 262 144 байта (256 КБ). Максимальный размер для Service Bus Premium и Event Hubs составляет 1 048 576 (100 МБ). В служебной шине не установлены определенные окна регулирования на уровне сеанса, но предусмотрен регулярный сброс окна в рамках управления потоком на уровне связи (см. следующий раздел).

Подключения, каналы и сеансы являются временными. Если базовое подключение прерывается, подключения, туннель TLS, контекст авторизации SASL и сеансы необходимо установить заново.

Обязательные порты для исходящего трафика AMQP

Клиенты, использующие подключения AMQP по протоколу TCP, должны открыть порты 5671 и 5672 в локальном брандмауэре. Вместе с этими портами может потребоваться открыть дополнительные порты, если включен компонент EnableLinkRedirect. EnableLinkRedirect — это новая функция обмена сообщениями, которая позволяет пропустить один прыжок при получении сообщений, что способствует повышению пропускной способности. Клиент начинает взаимодействовать напрямую с внутренней службой через диапазон портов 104XX, как показано на следующем рисунке.

Список портов назначения

Клиент .NET не сможет работать с SocketException ("Сделана попытка доступа к сокету методом, запрещенным правами доступа"), если эти порты заблокированы брандмауэром. Эту функцию можно отключить, указав EnableAmqpLinkRedirect=false в строке подключения, в результате чего клиенты будут взаимодействовать с удаленной службой через порт 5671.

Привязка AMQP WebSocket обеспечивает механизм туннелирования подключения AMQP через транспорт WebSocket. Эта привязка создает туннель через TCP-порт 443, который эквивалентен подключениям AMQP 5671. Используйте AMQP WebSockets, если вы находитесь за брандмауэром, который блокирует TCP-подключения через порты 5671, 5672, но разрешает TCP-подключения через порт 443 (https).

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

На снимке экрана показан сеанс, содержащий подключение по ссылке между двумя контейнерами.

Связи могут создаваться в контейнерах в любое время в рамках активного сеанса, что отличает протокол AMQP от многих других протоколов, включая HTTP и MQTT, где инициирование передачи и путь передачи является привилегией стороны, которая создает подключение через сокет.

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

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

В Service Bus узел напрямую соответствует очереди, теме, подписке или подочереди недоставленных писем в очереди или подписке. Имя узла, используемое в AMQP, — это относительное имя объекта в пространстве имен служебной шины. Имя очереди (например, myqueue) является также именем узла AMQP этой очереди. Подписка на раздел соответствует условиям соглашения HTTP API, так как она относится к коллекции ресурсов "подписки". Следовательно, для подписки sub из раздела mytopic имя узла AMQP будет иметь значение mytopic/subscriptions/sub.

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

Перемещения

Как только связь будет установлена, через нее можно передавать сообщения. В AMQP передача выполняется с помощью явного действия протокола (перформатив transfer), который перемещает сообщение от отправителя к получателю через канал. Передача считается завершенной, когда она "урегулирована", то есть обе стороны достигли общего понимания результата этой передачи.

На диаграмме показана передача сообщения между отправителем и получателем и последующая обработка.

В самом простом случае отправитель может отправлять сообщения "предварительно завершенными". Это означает, что клиент не заинтересован в результатах, и получатель не предоставляет информацию о результатах операции. Этот режим поддерживается служебной шиной на уровне протокола AMQP, но не представлен ни в одном из клиентских API-интерфейсов.

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

Состояние released (освобождено) — это особая форма отклонения, которая означает, что у получателя нет технических возражений в отношении передачи, но также нет интереса к её урегулированию. Такое бывает, например, когда сообщение доставляется клиенту служебной шины, который отклоняет это сообщение по причине того, что не может выполнить работу, возникающую в результате обработки сообщения, то есть сама по себе доставка сообщения выполняется без ошибок. Вариация этого состояния — это состояние modified (изменено), которое позволяет вносить изменения в сообщение при его публикации. Это состояние в настоящее время не используется в Service Bus.

Спецификация AMQP 1.0 определяет дополнительное состояние обработки — received (получено). Это состояние особенно удобно для обработки восстановления связей. Таким образом можно восстановить состояние связи и ожидающие доставки на основе нового подключения и сеанса, если предыдущее подключение и сеанс потеряны.

Служебная шина не поддерживает восстановление ссылок; если клиент теряет подключение к Служебной шине при неподтверждённой передаче сообщений, то эта передача теряется, и клиент должен повторно подключиться, восстановить ссылку и повторить передачу.

Таким образом, служебная шина и Центры событий поддерживают передачи "как минимум один раз", при которых отправитель может быть уверен, что сообщения приняты и сохранены. Но на уровне AMQP не поддерживаются передачи "ровно один раз", при которых система пытается восстановить связь и согласовать состояние доставки, чтобы не дублировать передачу сообщений.

Чтобы компенсировать возможные повторные отправки, служебная шина поддерживает обнаружение дубликатов как дополнительную функцию в очередях и топиках. Эта функция может быть активирована как опция. Детекция дубликатов фиксирует идентификаторы сообщений всех входящих сообщений в течение определённого пользователем временного окна, затем тихо отбрасывает все сообщения, отправленные с теми же идентификаторами сообщений в это же окно.

Управление потоком

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

Снимок экрана: журнал с именем источника, назначения, исходного порта, порта назначения и протокола. В первой строке порт назначения 10401 (0x28 A1) выделен черным цветом.

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

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

В роли отправителя, Service Bus отправляет сообщения, чтобы использовать все неиспользованные кредиты связи.

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

Блокировка сообщения снимается, когда передача переходит в одно из конечных состояний: accepted (принято), rejected (отклонено) или released (освобождено). Сообщение удаляется из Service Bus, когда терминальное состояние accepted (принято). Оно остается в Service Bus и будет доставлено следующему получателю, когда пересылка перейдет в другое состояние. Служебная шина автоматически переместит сообщение в очередь недоставленных сообщений объекта, когда будет достигнуто максимальное число доставок, разрешенное для объекта из-за повторяющихся отклонений или освобождений.

В интерфейсах API служебной шины такая возможность сейчас не предоставляется напрямую. Несмотря на это клиент протокола AMQP нижнего уровня может использовать модель разрешений на передачу, чтобы сменить взаимодействие с извлечением, при котором выдается одно разрешение для каждого запроса на получение, на модель с отправлением, при которой выдается большое количество разрешений на передачу. Это позволяет получать сообщения сразу, как только они станут доступными, без дополнительных согласований. Push-отправка поддерживается с помощью параметров свойства ServiceBusProcessor.PrefetchCount или ServiceBusReceiver.PrefetchCount. Если их значения не равны нулю, клиент AMQP использует их как кредит на соединение.

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

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

Стрелки в следующей таблице указывают направление потока выполнения.

Создание получателя сообщения

Клиент Cлужебная шина
--> присоединить(
name={link name},
handle={числовой идентификатор},
role=receiver (приемник)
source={имя сущности},
target={идентификатор ссылки клиента}
)
Клиент подключается к объекту в качестве получателя
Шина обслуживания отвечает, прикрепляя свой конец связи
              <-- attach()
имя={link name},
handle={числовой идентификатор},
role=sender,
source={имя сущности},
target={идентификатор ссылки клиента}
)

Создание отправителя сообщения

Клиент Service Bus
-- attach()>
name={link name},
handle={числовой дескриптор},
role=sender,
source={идентификатор ссылки клиента},
target={имя сущности}
)
Никаких действий
Никаких действий
              <-- attach()
name={link name},
handle={числовой идентификатор},
role=receiver,
source={идентификатор ссылки клиента},
target={имя сущности}
)

Создание отправителя сообщения (ошибка)

Клиент Cлужебная шина
--> присоединить(
name={link name},
handle={числовой дескриптор},
role=sender,
source={идентификатор ссылки клиента},
target={имя сущности}
)
Никаких действий
Никаких действий
              <-- attach()
name={link name},
handle={числовой идентификатор},
role=receiver,
source=NULL,
target=null
)

<-- отсоединение()
handle={числовой идентификатор},
closed=истина,
error={error info}
)

Закрытие получателя или отправителя сообщений

Клиент Cлужебная шина
-- отсоединение()>
handle={числовой дескриптор},
closed=истина
)
Никаких действий
Никаких действий
              <-- отсоединение()
handle={числовой дескриптор},
closed=true
)

Отправка (успешно)

Клиент Cлужебная шина
-- transfer()>
delivery-id={числовой дескриптор},
delivery-tag={двоичный дескриптор},
settled=false,more=false,
state=NULL,
resume=false
)
Никаких действий
Никаких действий
              <-- ликвидация()
role=receiver,
first={идентификатор доставки},
last={идентификатор доставки},
урегулировано=true,
state=принят
)

Отправка (ошибка)

Клиент Cлужебная шина
-- transfer()>
delivery-id={числовой дескриптор},
delivery-tag={двоичный дескриптор},
settled=false,,more=false,
state=NULL,
resume=false
)
Никаких действий
Никаких действий
              <-- ликвидация()
role=receiver,
first={идентификатор доставки},
last={идентификатор доставки},
урегулировано=true,
state=rejected()
error={error info}
)
)

Получение

Клиент Cлужебная шина
-- flow()>
link-credit=1
)
Никаких действий
Никаких действий
              < transfer()
delivery-id={числовой идентификатор},
delivery-tag={двоичный дескриптор},
урегулирован=false,
more=false,
state=NULL,
resume=false
)
-- распоряжение()>
role=receiver,
first={идентификатор доставки},
last={идентификатор доставки},
урегулировано=true,
state=принят
)
Никаких действий

Получение нескольких сообщений

Клиент Cлужебная шина
-- flow()>
link-credit=3
)
Никаких действий
Никаких действий
              < transfer()
delivery-id={числовой дескриптор},
delivery-tag={двоичный идентификатор},
settled=false,
more=false,
state=NULL,
resume=false
)
Никаких действий
              < transfer()
delivery-id={числовой идентификатор+1},
delivery-tag={бинарный хендл},
settled=ложь,
more=false,
state=NULL,
resume=false
)
Никаких действий
              < transfer()
delivery-id={числовой идентификатор+2},
delivery-tag={двоичный идентификатор},
settled=ложь,
more=false,
state=NULL,
resume=false
)
-- ликвидация()>
role=receiver,
first={идентификатор доставки},
last={delivery ID+2},
урегулировано=true,
state=принят
)
Никаких действий

Сообщения

В следующих разделах объясняется, какие свойства из стандартных разделов сообщений AMQP использует служебная шина, и как они соотносятся с набором API служебной шины.

Любое свойство, которое необходимо приложению, следует сопоставить с картой application-properties AMQP.

Имя поля Использование Имя API
прочный - -
приоритет - -
ttl Срок жизни сообщения TimeToLive
первый приобретатель - -
количество поставок - DeliveryCount

Свойства

Имя поля Использование Имя API
message-id Определяемый приложением идентификатор свободной формы для этого сообщения. Используется для обнаружения дубликатов. MessageId
user-id Определяемый приложением идентификатор пользователя, который не интерпретируется служебной шиной. Недоступно через API служебной шины.
to Определяемый приложением идентификатор назначения, который не интерпретируется Service Bus. Кому
subject Определяемый приложением идентификатор назначения сообщения, который не интерпретируется служебной шиной. Тема
reply-to Определяемый приложением индикатор пути ответа, который не интерпретируется служебной шиной. Ответ
correlation-id Определяемый приложением идентификатор корреляции, который не интерпретируется служебной шиной. CorrelationId
content-type Определяемый приложением индикатор типа содержимого, который не интерпретируется служебной шиной. ТипКонтента
content-encoding Индикатор кодирования содержимого, определяемый приложением, который не интерпретируется системой Service Bus. Недоступно через API служебной шины.
absolute-expiry-time Объявляет абсолютное время истечения срока действия сообщения. Игнорируется во входных данных (учитывается значение TTL заголовка), имеет приоритет в выходных данных. Недоступно через API служебной шины.
creation-time Объявляет время создания сообщения. Не используется Service Bus. Недоступно через API служебной шины.
group-id Определяемый приложением идентификатор связанного набора сообщений. Используется для сеансов ServiceBus. SessionId
group-sequence Счетчик, определяющий относительный порядковый номер сообщения в сеансе. Игнорируется служебной шиной. Недоступно через API служебной шины.
reply-to-group-id - Идентификатор сессии ответа

Заметки к сообщениям

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

Карта аннотирования Использование Имя API
x-opt-scheduled-enqueue-time Определяет, в какое время сообщение должно появиться на объекте. ScheduledEnqueueTime
x-opt-partition-key Определяемый приложением ключ, который указывает, в какой раздел должно попасть сообщение. PartitionKey
x-opt-via-partition-key Определяемое приложением значение ключа раздела в случае, когда используется транзакция для отправки сообщений через очередь передачи. TransactionPartitionKey
x-opt-enqueued-time Определяемое службой время в формате UTC, представляющее фактическое время добавления сообщения в очередь. Игнорируется во входных данных. EnqueuedTime
x-opt-sequence-number Определяемый службой уникальный номер, назначенный сообщению. SequenceNumber
x-opt-offset Определяемый службой порядковый номер постановки сообщения в очередь. EnqueuedSequenceNumber
x-opt-locked-until Определяется службой. Дата и время, до которых сообщение будет заблокировано в очереди или подписке. LockedUntil
x-opt-deadletter-source Определяется службой. Если сообщение получено из очереди отложенных сообщений, оно представляет источник исходного сообщения. DeadLetterSource

Возможность транзакций

Транзакция объединяет две или несколько операций в область выполнения. По своей природе такая транзакция должна обеспечивать, что все операции данной группы либо успешно выполняются совместно, либо терпят неудачу совместно. Операции группируются по идентификатору txn-id.

Для транзакционного взаимодействия клиент действует как transaction controller, контролируя операции, которые должны быть сгруппированы вместе. Служба "Служебная шина" выступает в качестве transactional resource и выполняет задачи, которые запрашивает transaction controller.

Клиент и служба взаимодействуют через control link, что устанавливается клиентом. Сообщения declare и discharge отправляются контроллером по каналу управления для выделения и завершения транзакций соответственно (они не определяют границ для работы с транзакциями). Фактическая передача данных не осуществляется через эту ссылку. Каждая запрошенная транзакционная операция явно идентифицируется с требуемым txn-id значением и, следовательно, может возникать на любой ссылке в соединении. Если канал управления закроется, несмотря на созданные им неразгруженные транзакции, все такие транзакции немедленно откатываются, и попытки выполнить дальнейшую работу с ними приведут к ошибке. Сообщения по каналу управления не должны предварительно согласовываться.

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

Запуск транзакции

Чтобы начать работу транзакций, контроллер должен получить txn-id от координатора. Для этого он отправляет сообщения с типом declare. Если объявление выполнено успешно, координатор отправляет в ответ результаты обработки сообщения с назначенным txn-id.

Клиент (контроллер) Направление Служебная шина (координатор)
присоединить()
name={link name},
... ,
role=sender,
target=Coordinator
)
------>
<------
присоединить
name={link name},
... ,
target=Координатор()
)
трансфер()
delivery-id=0, ...)
{ AmqpValue (Declare())}
------>
<------
ликвидация() 
first=0, last=0,
state=Declared()
txn-id={идентификатор транзакции}
))

Разгрузка транзакций

Контроллер завершает работу с транзакциями, отправляя координатору сообщение discharge. Контроллер указывает, что он желает зафиксировать или откатить выполнение транзакции, устанавливая флаг fail в теле сообщения о разъединении. Если координатору не удается завершить разгрузку, сообщение отклоняется с результатом, который содержит transaction-error.

Примечание: значение fail=true означает откат транзакции, а fail=false — подтверждение.

Клиент (контроллер) Направление Служебная шина (координатор)
трансфер()
delivery-id=0, ...)
{ AmqpValue (Declare())}
------>
<------
ликвидация() 
first=0, last=0,
state=Declared()
txn-id={идентификатор транзакции}
))
. . .
Работа с транзакциями
на других ссылках
. . .
трансфер()
delivery-id=57, ...)
{ AmqpValue (
Discharge(txn-id=0,
fail=false)
)}
------>
<------
ликвидация() 
first=57, last=57,
state=Accepted())

Отправка сообщения в транзакции

Все транзакционные операции выполняются с транзакционным состоянием transactional-state, который содержит txn-id. При отправке сообщений транзакционное состояние передается кадром передачи сообщения.

Клиент (контроллер) Направление Сервисная шина (координатор)
перенос
delivery-id=0, ...)
{ AmqpValue (Declare())}
------>
<------
ликвидация() 
first=0, last=0,
state=Declared()
txn-id={идентификатор транзакции}
))
трансфер()
handle=1,
delivery-id=1,
состояние=
TransactionalState(
txn-id=0)
)
{ payload }
------>
<------
ликвидация() 
first=1, last=1,
state=TransactionalState(
txn-id=0,
outcome=Accepted()
))

Удаление сообщения в транзакции

Обработка сообщения предусматривает такие операции, как Complete / Abandon / DeadLetter / Defer. Для выполнения этих операций в рамках транзакции передайте transactional-state с параметром диспозиции.

Клиент (контроллер) Направление Служебная шина (координатор)
трансфер
delivery-id=0, ...)
{ AmqpValue (Declare())}
------>
<------
расположение() 
first=0, last=0,
state=Declared()
txn-id={идентификатор транзакции}
))
<------
трансфер()
handle=2,
delivery-id=11,
state=NULL)
{ payload }
ликвидация() 
first=11, last=11,
state=TransactionalState(
txn-id=0,
outcome=Accepted()
))
------>

Расширенные возможности служебной шины

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

Примечание.

Дополнительные операции обмена сообщениями служебной шины поддерживаются с помощью шаблона "запрос — ответ". Дополнительные сведения об этих операциях см. в статье AMQP 1.0 в служебной шине Microsoft Azure: операции c запросами и ответами.

Управление AMQP

Спецификация управления AMQP — это первое черновое расширение, рассмотренное в этой статье. Эта спецификация определяет набор протоколов, расположенных над уровнем протокола AMQP, которые позволяют выполнять взаимодействия по управлению с инфраструктурой обмена сообщениями по протоколу AMQP. Спецификация определяет такие универсальные операции, как создание, чтение, обновление и удаление, для управления объектами в инфраструктуре обмена сообщениями, а также набор операций запросов.

Для всех этих жестов требуется взаимодействие "запрос — ответ" между клиентом и инфраструктурой обмена сообщениями. Поэтому спецификация определяет реализацию этого шаблона взаимодействия поверх AMQP: клиент подключается к инфраструктуре обмена сообщениями, инициирует сеанс, а затем создает пару связей. В одной связи клиент выступает в роли отправителя, а в другой — в качестве получателя, тем самым создавая пару связей, которая может выполнять роль двустороннего канала.

Логическая операция Клиент Cлужебная шина
Создание пути "запрос-ответ"
--> присоединить(
name={имя ссылки},
handle={числовой идентификатор},
role=sender,
source=NULL,
target="myentity/$management"
)
Никаких действий
Создание пути "запрос-ответ" Никаких действий
              <-- attach()
name={имя ссылки},
handle={числовой дескриптор},
role=receiver,
source=NULL,
target="myentity"
)
Создание пути "запрос-ответ"
--> присоединить(
name={имя ссылки},
handle={числовой идентификатор},
role=receiver,
source="myentity/$management",
target="myclient$id"
)
Создание пути "запрос-ответ" Никаких действий
              <-- attach()
name={имя ссылки},
handle={числовой дескриптор},
role=sender,
source="myentity",
target="myclient$id"
)

При наличии этой пары связей реализация модели "запрос — ответ" выполняется очень просто: запросом считается сообщение, отправленное в объект в инфраструктуре обмена сообщениями, которая поддерживает эту модель. В этом запросе-сообщении для поля reply-to в разделе properties установлен целевой идентификатор для связи, через которую отправляется ответ. Объект обработки обрабатывает запрос и предоставляет ответ через связь, целевой идентификатор которой соответствует указанному идентификатору в поле reply-to.

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

Обмен сообщениями, используемый для протокола управления и для всех других протоколов, использующих тот же шаблон, происходит на уровне приложения; Они не определяют новые жесты уровня протокола AMQP. Это сделано намеренно, чтобы приложения могли сразу применять эти расширения с совместимыми стеками AMQP 1.0.

служебная шина в настоящее время не реализует ни одну из основных функций спецификации управления, но шаблон запроса и ответа, определенный спецификацией управления, является основой для функции безопасности на основе утверждений и почти для всех расширенных возможностей, описанных в следующих разделах:

Авторизация на основе утверждений

Черновик спецификации для авторизации на основе утверждений (CBS) в AMQP основан на шаблоне "запрос — ответ" спецификации управления и описывает обобщенную модель использования маркеров федеративной безопасности с протоколом AMQP.

Модель безопасности AMQP по умолчанию, описанная во введении, основана на SASL и интегрируется при помощи подтверждения подключения AMQP. При использовании SASL предоставляется расширяемая модель, для которой определен набор механизмов. Любой протокол, в котором используется SASL, может использовать этот набор. К этим механизмам относятся следующие: PLAIN для передачи имен пользователей и паролей, EXTERNAL для привязки к безопасности на уровне TLS, ANONYMOUS для выражения отсутствия явной проверки подлинности или авторизации и широкий набор дополнительных механизмов, позволяющих передавать учетные данные или маркеры для проверки подлинности и (или) авторизации.

Интеграция SASL в протоколе AMQP имеет два недостатка:

  • Все учетные данные и маркеры ограничены подключением. Инфраструктура обмена сообщениями может желать предоставить дифференцированный контроль доступа на основе каждой сущности; например, позволяя обладателю токена отправлять сообщения в очередь A, но не в очередь B. Поскольку контекст авторизации привязан к подключению, невозможно использовать единственное подключение и одновременно разные токены доступа для очереди A и очереди B.
  • Как правило, маркеры доступа действительны в течение ограниченного периода времени. Эта действительность требует, чтобы пользователь периодически повторно получал токены. Это позволяет поставщику токенов отклонить выдачу нового токена, если изменятся разрешения пользователя на доступ. Подключения AMQP могут длиться долгое время. Модель SASL предоставляет только возможность задать токен во время подключения, что означает, что инфраструктура обмена сообщениями должна либо отключить клиента, когда срок действия токена истекает, либо она должна принять риск продолжения обмена сообщениями с клиентом, права доступа которого могли быть отозваны в это время.

Спецификация CBS AMQP, реализуемая служебной шиной, элегантно обходит обе эти проблемы: клиент может связать маркеры доступа с каждым узлом и обновить их до истечения срока действия, не прерывая поток сообщений.

CBS определяет виртуальный узел управления $cbs, который должна предоставить инфраструктура обмена сообщениями. Узел управления принимает токены от имени любых других узлов в инфраструктуре обмена сообщениями.

Жест протокола — это обмен данными по типу "запрос-ответ", как определено в спецификации управления. Это означает, что клиент устанавливает пару связей с узлом $cbs, а затем передает запрос в исходящую связь, после чего ожидает ответа во входящей связи.

Сообщение запроса обладает следующими свойствами приложения.

Ключ Необязательно Тип значения Значение содержимого
operation Нет строка put-token
type Нет строка Тип вставляемого маркера.
name Нет строка "Аудитория", к которой относится токен.
expiration Да отметка времени Время истечения срока действия токена.

Свойство name определяет объект, с которым необходимо связать маркер. В служебной шине это путь к очереди, разделу или подписке. Свойство type определяет тип маркера:

Тип маркера Описание токена Тип тела Примечания.
jwt Веб-токен JSON (JWT) Значение AMQP (строка)
servicebus.windows.net:sastoken Токен SAS для службы шины Значение AMQP (строка) -

Токены предоставляют права. Служебная шина распознает три основных права: право "Отправка" позволяет отправлять, право "Прием" позволяет получать, а право "Управление" позволяет управлять объектами. Маркеры SAS служебной шины ссылаются на правила, настроенные в пространстве имен или объекте, и эти правила настраиваются с помощью этих прав. Подписание токена ключом, связанным с этим правилом, таким образом, делает токен выразителем соответствующих прав. Маркер, связанный с объектом с помощью put-token, позволит подключенному клиенту взаимодействовать с объектом, используя права маркера. Для связи, в которой клиент принимает роль отправителя, требуются права на отправку, а для роли получателя — права на прослушивание.

Для сообщения ответа предусмотрены следующие значения свойств приложения.

Ключ Необязательно Тип значения Значение содержимого
status-code Нет INT Код ответа HTTP [RFC2616].
status-description Да строка Описание состояния.

Клиент может вызвать запрос put-token несколько раз для любого объекта в инфраструктуре обмена сообщениями. Маркеры ограничиваются текущим клиентом и привязываются к текущему подключению. Это означает, что сервер удаляет хранимые маркеры после разрыва подключения.

Текущая реализация шины Service Bus разрешает CBS только в сочетании с методом SASL "ANONYMOUS". Перед началом подтверждения SASL всегда должно быть установлено соединение SSL/TLS.

Таким образом, выбранный клиент AMQP 1.0 должен поддерживать механизм ANONYMOUS. Анонимный доступ означает, что начальное взаимодействие при подключении, включая создание первого сеанса, происходит без идентификации Service Bus того, кто устанавливает соединение.

После установки подключения и создания сеанса единственными допустимыми операциями являются подключение связей к узлу $cbs и отправка запроса put-token. Допустимый маркер должен быть успешно установлен с помощью запроса put-token для определенного узла объекта в течение 20 секунд после установления подключения, в противном случае служебная шина разрывает соединение в одностороннем порядке.

Затем клиент несет ответственность за отслеживание срока действия токенов. По истечении срока действия токена Service Bus незамедлительно разрывает все соединения с соответствующей сущностью. Чтобы избежать возникновения этой проблемы, клиент может в любое время заменить токен для узла новым токеном через виртуальный узел управления $cbs с помощью того же жеста put-token, без нарушения трафика полезных данных, который проходит по различным ссылкам.

Функция отправки через посредника

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

С помощью данной функции вы создаете отправителя и устанавливаете канал связи с via-entity. При установлении связи передаются дополнительные сведения для определения истинного получателя сообщений/передач по этой связи. После успешного присоединения все сообщения, отправленные по этому каналу, будут автоматически перенаправляться к сущности назначения через промежуточную сущность.

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

Клиент Направление Cлужебная шина
присоединить
name={link name},
role=sender,
source={идентификатор ссылки клиента},
target={via-entity},
properties=map [(
com.microsoft:transfer-destination-address=
{destination-entity} )]
)
------>
<------
присоединить
name={link name},
role=receiver,
source={идентификатор ссылки клиента},
target={via-entity},
properties=map [(
com.microsoft:transfer-destination-address=
{destination-entity} )] )

Дополнительные сведения об AMQP см. в статье Общие сведения о служебной шине AMQP.