Секционированные очереди и разделы

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

Примечание.

Существуют некоторые различия между SKU 'Базовый', 'Стандартный' и 'Премиум' в плане разделения.

  • Секционирование доступно при создании сущностей для всех очередей и топиков в SKU уровня "Базовый" или "Стандартный". Пространство имен может содержать как секционированные, так и не секционированные сущности.
  • Секциирование доступно при создании пространства имен для премиум SKU обмена сообщениями, и все очереди и темы в этом пространстве имен разбиваются на секции. Все ранее перенесенные секционированные сущности в пространствах имен Premium продолжают работать должным образом.
  • При включении партицирования в SKU "Базовый" или "Стандартный" всегда создается 16 партиций.
  • При включении разделения в SKU уровня "Премиум" необходимо указать количество разделов во время создания пространства имен.

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

Принцип работы

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

Когда клиент хочет получить сообщение из разделённой очереди или подписки на разделённую тему, Service Bus запрашивает сообщения из всех разделов. Он возвращает первое сообщение, которое он получает от любого из хранилищ сообщений получателю. Служебная шина кэширует другие сообщения и возвращает их при получении дополнительных запросов. Получающий клиент не знает о секционирования. Поведение секционированных очередей или тем (например, чтение, завершение, отложение, мертвописьмо, предварительная выборка) идентично поведению обычного объекта.

Операция просмотра для неразделённой сущности всегда возвращает самое старое сообщение, но не для разделённой сущности. Вместо этого возвращается самое старое сообщение в одной из секций, чей брокер сообщений ответил первым. Нет никакой гарантии, что возвращенное сообщение является самым старым во всех разделах.

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

Примечание.

Операция просмотра возвращает самое старое сообщение из секции на основе его порядкового номера. Для секционированных сущностей порядковый номер является относительным по отношению к разделу. Дополнительные сведения см. в статье Последовательность и метки времени сообщений.

Использование ключей раздела

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

Использование ключа раздела

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

В зависимости от сценария в качестве ключа секции используются разные свойства сообщения:

SessionId: если сообщение имеет набор свойств идентификатора сеанса, служебная шина использует его в качестве ключа секции. Таким образом, один и тот же брокер сообщений обрабатывает все сообщения, принадлежащие одному сеансу. С помощью сеансов Service Bus гарантирует порядок доставки сообщений, а также согласованность состояний сеанса.

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

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

Не использование ключа раздела

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

Более подробно компромисс между доступностью (нет ключа раздела) и целостностью (с использованием ключа раздела) рассматривается в статье Доступность и согласованность в Центрах событий. За исключением того, что идентификатор раздела не предоставляется пользователям, эти сведения применяются аналогично разделённым сущностям Service Bus.

Чтобы предоставить служебной шине достаточно времени для постановки сообщения в очередь в другую секцию, значение времени ожидания, определяемое клиентом, который отправляет сообщение, должно быть больше 15 секунд. Рекомендуется использовать значение по умолчанию 60 секунд.

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

Дополнительные разделы

Использование транзакций с секционированными сущностями

Сообщения, отправляемые в рамках транзакции, должны указывать ключ секции. Ключ может принимать одно из следующих свойств: SessionId, PartitionKey или MessageId. Все сообщения, отправляемые в рамках одной транзакции, должны указывать один и тот же ключ секции. При попытке отправить сообщение без ключа раздела в рамках транзакции Service Bus возвращает исключение недопустимой операции. При попытке отправить несколько сообщений с разными ключами раздела в рамках одной транзакции Service Bus возвращает исключение о недопустимой операции. Например:

CommittableTransaction committableTransaction = new CommittableTransaction();
using (TransactionScope ts = new TransactionScope(committableTransaction))
{
    ServiceBusMessage msg = new ServiceBusMessage("This is a message");
    msg.PartitionKey = "myPartitionKey";
    await sender.SendMessageAsync(msg); 
    ts.Complete();
}
committableTransaction.Commit();

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

Использование транзакций в сеансах с секционированными сущностями

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

В отличие от обычных (неразделенных) очередей или тем, нельзя использовать одну транзакцию для отправки нескольких сообщений в разные сеансы. Если вы попытаетесь выполнить эту операцию, Service Bus вернёт исключение недопустимой операции. Например:

CommittableTransaction committableTransaction = new CommittableTransaction();
using (TransactionScope ts = new TransactionScope(committableTransaction))
{
    ServiceBusMessage msg = new ServiceBusMessage("This is a message");
    msg.SessionId = "mySession";
    await sender.SendMessageAsync(msg); 
    ts.Complete();
}
committableTransaction.Commit();

Автоматическая переадресация сообщений для секционированных сущностей

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

Рекомендации и советы

  • Функции высокой согласованности: если сущность использует такие функции, как сеансы, обнаружение повторяющихся данных или явный контроль ключа секционирования, операции обмена сообщениями всегда направляются в определенную секцию. При большом трафике в каком-либо из разделов или неработоспособности базового хранилища эти операции не выполняются и доступность снижается. В целом согласованность всё ещё намного выше, чем у неразделённых сущностей. Проблемы возникают только в подмножестве трафика, а не во всем трафике. Дополнительные сведения см. в этом обсуждении доступности и целостности.
  • Управление. Операции создания, обновления и удаления должны быть выполнены для всех секций сущности. Если какой-либо раздел неработоспособен, это может привести к сбоям в работе этих операций. Для операции получения требуется, чтобы информация, такая как количество сообщений, была консолидирована из всех разделов. Если какой-либо раздел неисправен, статус доступности сущности отображается как ограниченный.
  • Сценарии сообщений с низким объемом: для таких сценариев, особенно при использовании протокола HTTP, может потребоваться выполнить несколько операций получения, чтобы получить все сообщения. Для запросов на получение фронт-энд выполняет приём на всех разделах и кэширует все полученные ответы. Последующий запрос на получение по тому же подключению выигрывает от этого кэширования, и задержки при получении снижаются. Однако если у вас несколько подключений или используется HTTP, для каждого запроса устанавливается новое подключение. Таким образом, нет никаких гарантий того, что он приземляется на том же узле. Если все имеющиеся сообщения блокируются и кэшируются в другом внешнем интерфейсе, операция получения возвращает значение NULL. Когда в конечном итоге срок действия сообщений истекает, их снова можно получать. Рекомендуется использовать функцию keep-alive для HTTP. При использовании секционирования в сценариях с низким объемом операции получения могут занять больше времени, чем ожидалось. Поэтому не используйте секционирование в этих сценариях. Для повышения производительности удалите все существующие секционированные сущности и создайте их заново, отключив секционирование.
  • Обзор/просмотр сообщений: операция просмотра не всегда возвращает число запрошенных сообщений. Две распространенные причины объясняют это поведение. Одна из причин заключается в том, что совокупный размер коллекции сообщений превышает максимальный размер. Другая причина заключается в том, что в секционированных очередях или разделах секция может не иметь достаточно сообщений для возврата запрошенного количества сообщений. Как правило, если приложение хочет взглянуть или просмотреть определенное количество сообщений, оно должно многократно вызывать операцию просмотра, пока не получит это количество сообщений, или больше нет сообщений для просмотра. Дополнительные сведения, включая примеры кода, см. в разделе Просмотр сообщений.

Ограничения секционированных сущностей

В настоящее время Service Bus накладывает следующие ограничения на разделяемые очереди и темы:

  • Секционированные очереди и разделы не поддерживают отправку сообщений, принадлежащих разным сеансам, в одной транзакции.
  • Service Bus на данный момент поддерживает до 100 секционированных очередей или топиков на каждом пространстве имен для уровней "Базовый" и "Стандартный". Каждая секционированная очередь или раздел учитывается в квоте в 10 000 сущностей на пространство имен.

Следующие шаги

Секционирование можно включить с помощью портала Azure, PowerShell, интерфейса командной строки, шаблона Диспетчера ресурсов, .NET, Java, Python и JavaScript. Дополнительные сведения см. в разделе "Включение секционирования" ("Базовый" или "Стандартный")

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