Шаблон очереди с приоритетом

Служебная шина Azure

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

Контекст и проблема

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

Решение

Очередь обычно является структурой первого и первого выхода (FIFO), а потребители обычно получают сообщения в том же порядке, что и в очереди. Тем не менее некоторые очереди сообщений поддерживают приоритет обмена сообщениями. Приложение, которое публикует сообщение, может назначить приоритет. Сообщения в очереди автоматически переупорядочены таким образом, чтобы те, которые имеют более высокий приоритет, были получены до тех, кто имеет более низкий приоритет. На этой схеме показан процесс:

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

Примечание.

Большинство реализаций очереди сообщений поддерживают несколько потребителей. (См. раздел Шаблон конкурирующих потребителей.) Количество потребительских процессов можно увеличить и уменьшить на основе спроса.

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

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

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

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

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

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

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

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

Рекомендации

Рассмотрим следующие моменты, когда вы решите, как реализовать этот шаблон:

  • Определяйте приоритеты в контексте решения. Например, высокоприоритетное сообщение может быть определено как сообщение, которое должно обрабатываться в течение 10 секунд. Определите требования к обработке элементов с высоким приоритетом и ресурсы, которые должны быть выделены для удовлетворения ваших критериев.

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

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

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

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

  • Стратегия использования отдельных очередей на основе приоритета сообщения рекомендуется для систем с несколькими четко определенными приоритетами.

  • Система может логически определить приоритеты сообщений. Например, вместо того, чтобы явные сообщения с высоким и низким приоритетом, можно назначить сообщения как "оплата клиента" или "неоплачиваемого клиента". Затем система может выделить больше ресурсов для обработки сообщений от оплаты клиентов.

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

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

Когда следует использовать этот шаблон

Этот шаблон полезен в следующих ситуациях:

  • система должна обработать несколько задач с различными приоритетами;

  • Разные пользователи или клиенты должны обслуживаться с различными приоритетами.

Проектирование рабочей нагрузки

Архитектор должен оценить, как шаблон очереди приоритета можно использовать в проектировании рабочей нагрузки для решения целей и принципов, описанных в основных принципах Платформы Azure Well-Architected Framework. Например:

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

- Критически важные потоки RE:02
- Задания RE:07 Фоновые задания
Эффективность производительности помогает рабочей нагрузке эффективно соответствовать требованиям путем оптимизации масштабирования, данных, кода. Разделение элементов на основе приоритета бизнеса позволяет сосредоточить усилия на производительности на наиболее чувствительных к времени работах.

- Критически важные потоки PE:09

Как и любое решение по проектированию, рассмотрите любые компромиссы по целям других столпов, которые могут быть представлены с этим шаблоном.

Пример

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

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

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

На предыдущей схеме приложение создает несколько сообщений и назначает настраиваемое свойство, вызываемое Priority в каждом сообщении. Priority имеет значение High или Low. Приложение отправляет эти сообщения в раздел. В разделе есть две связанные подписки, которые фильтруют сообщения на Priority основе свойства. Одна подписка принимает сообщения с заданным HighсвойствомPriority. Другой принимает сообщения с заданным LowсвойствомPriority. Пул потребителей считывает сообщения из каждой подписки. Подписка с высоким приоритетом имеет более крупный пул, и эти потребители могут работать на более мощных компьютерах, имеющих более доступные ресурсы, чем компьютеры для пула с низким приоритетом.

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

Решение PriorityQueue на сайте GitHub основано на этом подходе. Это решение содержит проекты функций Azure с именем PriorityQueueConsumerHigh и PriorityQueueConsumerLow. Эти проекты функций Azure интегрируются с служебная шина с помощью триггеров и привязок. Они подключаются к различным подпискам, определенным в ServiceBusTrigger и реагирующих на входящие сообщения.

public static class PriorityQueueConsumerHighFn
{
    [FunctionName("HighPriorityQueueConsumerFunction")]
    public static void Run(
      [ServiceBusTrigger("messages", "highPriority", Connection = "ServiceBusConnection")]string highPriorityMessage,
      ILogger log)
    {
        log.LogInformation($"C# ServiceBus topic trigger function processed message: {highPriorityMessage}");
    }
}

Администратор может настроить, сколько экземпляров функций в службе приложение Azure может масштабироваться. Это можно сделать, настроив параметр "Ограничить горизонтальное масштабирование" из портал Azure, задав максимальное ограничение горизонтального масштабирования для каждой функции. Обычно требуется иметь больше экземпляров PriorityQueueConsumerHigh функции, чем PriorityQueueConsumerLow функция. Эта конфигурация гарантирует, что сообщения с высоким приоритетом считываются из очереди быстрее, чем сообщения с низким приоритетом.

Другой проект PriorityQueueSenderсодержит функцию Azure с активацией времени, настроенную для выполнения каждые 30 секунд. Эта функция интегрируется с служебная шина через выходную привязку и отправляет пакеты сообщений с низким и высоким приоритетом в IAsyncCollector объект. Когда функция отправляет сообщения в раздел, связанный с подписками, используемыми PriorityQueueConsumerHigh и PriorityQueueConsumerLow функциями, определяет приоритет с помощью настраиваемого Priority свойства, как показано ниже:

public static class PriorityQueueSenderFn
{
    [FunctionName("PriorityQueueSenderFunction")]
    public static async Task Run(
        [TimerTrigger("0,30 * * * * *")] TimerInfo myTimer,
        [ServiceBus("messages", Connection = "ServiceBusConnection")] IAsyncCollector<ServiceBusMessage> collector)
    {
        for (int i = 0; i < 10; i++)
        {
            var messageId = Guid.NewGuid().ToString();
            var lpMessage = new ServiceBusMessage() { MessageId = messageId };
            lpMessage.ApplicationProperties["Priority"] = Priority.Low;
            lpMessage.Body = BinaryData.FromString($"Low priority message with Id: {messageId}");
            await collector.AddAsync(lpMessage);

            messageId = Guid.NewGuid().ToString();
            var hpMessage = new ServiceBusMessage() { MessageId = messageId };
            hpMessage.ApplicationProperties["Priority"] = Priority.High;
            hpMessage.Body = BinaryData.FromString($"High priority message with Id: {messageId}");
            await collector.AddAsync(hpMessage);
        }
    }
}

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

При реализации этого шаблона могут оказаться полезными следующие ресурсы:

  • Пример, демонстрирующий этот шаблон, на GitHub.

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

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

При реализации этого шаблона могут оказаться полезными следующие шаблоны:

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

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