Padrão de Fila de PrioridadePriority Queue pattern

Defina prioridades dos pedidos enviados para os serviços, de modo a que os pedidos com uma prioridade mais alta sejam recebidos e processados mais rapidamente do que aqueles com uma prioridade mais baixa.Prioritize requests sent to services so that requests with a higher priority are received and processed more quickly than those with a lower priority. Este padrão é útil em aplicações que oferecem diferentes garantias de nível de serviço para clientes individuais.This pattern is useful in applications that offer different service level guarantees to individual clients.

Contexto e problemaContext and Problem

As aplicações podem delegar tarefas específicas para outros serviços, por exemplo, realizar o processamento em segundo plano ou integrar com outros serviços ou aplicações.Applications can delegate specific tasks to other services, for example, to perform background processing or to integrate with other applications or services. Na cloud, uma fila de mensagens é normalmente utilizada para delegar tarefas para processamento em segundo plano.In the cloud, a message queue is typically used to delegate tasks to background processing. Em muitos casos, a ordem pela qual os pedidos são recebidos por um serviço não é importante.In many cases the order requests are received in by a service isn't important. No entanto, em alguns casos, é necessário atribuir prioridades a pedidos específicos.In some cases, though, it's necessary to prioritize specific requests. Estes pedidos devem ser processados antes dos pedidos com prioridade inferior que foram enviados anteriormente pela aplicação.These requests should be processed earlier than lower priority requests that were sent previously by the application.

SoluçãoSolution

Normalmente, uma fila é uma estrutura first-in, first-out (FIFO) e os consumidores normalmente recebem mensagens pela mesma ordem em que são publicadas na fila.A queue is usually a first-in, first-out (FIFO) structure, and consumers typically receive messages in the same order that they were posted to the queue. No entanto, algumas filas de mensagens suportam mensagens de prioridade.However, some message queues support priority messaging. A aplicação a publicar uma mensagem pode atribuir uma prioridade e as mensagens na fila são automaticamente reordenadas para que aquelas com uma prioridade superior sejam recebidas antes das outras com uma prioridade inferior.The application posting a message can assign a priority and the messages in the queue are automatically reordered so that those with a higher priority will be received before those with a lower priority. A figura mostra uma fila com mensagens de prioridade.The figure illustrates a queue with priority messaging.

Figura 1 – Utilização de um mecanismo de colocação em fila que suporta a priorização das mensagens

A maioria das implementações da fila de mensagens suportam vários consumidores (de acordo com o Padrão de Consumidores Concorrentes) e o número de processos de consumidor pode ser aumentado ou reduzido verticalmente, consoante o pedido.Most message queue implementations support multiple consumers (following the Competing Consumers pattern), and the number of consumer processes can be scaled up or down depending on demand.

Nos sistemas que não suportam filas de mensagens baseadas na prioridade, uma solução alternativa consiste em manter uma fila separada para cada prioridade.In systems that don't support priority-based message queues, an alternative solution is to maintain a separate queue for each priority. A aplicação é responsável por publicar mensagens na fila adequada.The application is responsible for posting messages to the appropriate queue. Cada fila pode ter um conjunto separado de consumidores.Each queue can have a separate pool of consumers. As filas de prioridade superior podem ter um conjunto maior de consumidores em execução em hardware mais rápido do que as filas de prioridade inferior.Higher priority queues can have a larger pool of consumers running on faster hardware than lower priority queues. A figura seguinte ilustra a utilização de filas de mensagens separadas para cada prioridade.The next figure illustrates using separate message queues for each priority.

Figura 2 – Utilização de filas de mensagens separadas para cada prioridade

Uma variação nesta estratégia passa pela utilização de um único conjunto de consumidores que verifica a existência de mensagens em filas de alta prioridade em primeiro lugar. Só depois é que inicia a obtenção de mensagens de filas de prioridade inferior.A variation on this strategy is to have a single pool of consumers that check for messages on high priority queues first, and only then start to fetch messages from lower priority queues. Existem algumas diferenças semânticas entre uma solução que utiliza um único conjunto de processos de consumidor (com uma fila única que suporta mensagens com prioridades diferentes ou com várias filas que processam mensagens de uma única prioridade) e uma solução que utiliza várias filas com um conjunto separado para cada fila.There are some semantic differences between a solution that uses a single pool of consumer processes (either with a single queue that supports messages with different priorities or with multiple queues that each handle messages of a single priority), and a solution that uses multiple queues with a separate pool for each queue.

Na abordagem de conjunto único, as mensagens de prioridade superior são sempre recebidas e processadas antes das mensagens de prioridade inferior.In the single pool approach, higher priority messages are always received and processed before lower priority messages. Em teoria, as mensagens com uma prioridade muito baixa podem ser continuamente substituídas e podem nunca ser processadas.In theory, messages that have a very low priority could be continually superseded and might never be processed. Na abordagem de vários conjuntos, as mensagens de prioridade inferior vão ser eventualmente processadas, mas não tão rapidamente como as de prioridade superior (dependendo do tamanho relativo dos conjuntos e dos recursos à sua disposição).In the multiple pool approach, lower priority messages will always be processed, just not as quickly as those of a higher priority (depending on the relative size of the pools and the resources that they have available).

A utilização de um mecanismo de colocação em fila de prioridade pode fornecer as seguintes vantagens:Using a priority queuing mechanism can provide the following advantages:

  • Permite que as aplicações satisfaçam os requisitos comerciais que precisam da priorização da disponibilidade ou do desempenho, tal como a oferta de diferentes níveis de serviço a grupos específicos de clientes.It allows applications to meet business requirements that require prioritization of availability or performance, such as offering different levels of service to specific groups of customers.

  • Pode ajudar a minimizar os custos operacionais.It can help to minimize operational costs. Na abordagem de fila única, pode reduzir o número de consumidores se necessário.In the single queue approach, you can scale back the number of consumers if necessary. As mensagens de alta prioridade vão continuar a ser processadas em primeiro lugar (embora possivelmente de forma mais lenta) e as mensagens de prioridade inferior podem ser adiadas ainda mais.High priority messages will still be processed first (although possibly more slowly), and lower priority messages might be delayed for longer. Se tiver implementado a abordagem de várias filas de mensagens com conjuntos separados de consumidores para cada fila, poderá reduzir o conjunto de consumidores de filas com prioridade inferior ou, inclusivamente, suspender o processamento de algumas filas de prioridade muito baixa ao parar todos os consumidores à escuta de mensagens nessas filas.If you've implemented the multiple message queue approach with separate pools of consumers for each queue, you can reduce the pool of consumers for lower priority queues, or even suspend processing for some very low priority queues by stopping all the consumers that listen for messages on those queues.

  • A abordagem de várias filas de mensagens pode ajudar a maximizar o desempenho e a escalabilidade da aplicação ao particionar mensagens com base nos requisitos de processamento.The multiple message queue approach can help maximize application performance and scalability by partitioning messages based on processing requirements. Por exemplo, as tarefas essenciais podem ser priorizadas para serem processadas por recetores que são executados de imediato enquanto as tarefas em segundo plano menos importantes podem ser processadas por recetores agendados para serem executados em períodos menos ocupados.For example, vital tasks can be prioritized to be handled by receivers that run immediately while less important background tasks can be handled by receivers that are scheduled to run at less busy periods.

Problemas e consideraçõesIssues and Considerations

Na altura de decidir como implementar este padrão, considere os seguintes pontos:Consider the following points when deciding how to implement this pattern:

Defina as prioridades no contexto da solução.Define the priorities in the context of the solution. Por exemplo, uma prioridade elevada pode significar que as mensagens devem ser processadas num intervalo de dez segundos.For example, high priority could mean that messages should be processed within ten seconds. Identifique os requisitos para o processamento de itens de alta prioridade e os outros recursos que devem ser alocados para satisfazer estes critérios.Identify the requirements for handling high priority items, and the other resources that should be allocated to meet these criteria.

Decida se todos os itens de alta prioridade têm de ser processados antes de quaisquer itens de prioridade inferior.Decide if all high priority items must be processed before any lower priority items. Se as mensagens estiverem a ser processadas por um único conjunto de consumidores, terá de disponibilizar um mecanismo que possa prevenir e suspender uma tarefa que está a processar uma mensagem de baixa prioridade caso fique disponível uma mensagem de prioridade superior.If the messages are being processed by a single pool of consumers, you have to provide a mechanism that can preempt and suspend a task that's handling a low priority message if a higher priority message becomes available.

Na abordagem de várias filas, quando utiliza um único conjunto de processos de consumidor que fica à escuta em todas as filas em vez de um conjunto de consumidores dedicado para cada fila, o consumidor deve aplicar um algoritmo que assegure sempre o processamento das mensagens de filas de prioridade superior antes das filas de prioridade inferior.In the multiple queue approach, when using a single pool of consumer processes that listen on all queues rather than a dedicated consumer pool for each queue, the consumer must apply an algorithm that ensures it always services messages from higher priority queues before those from lower priority queues.

Monitorize a velocidade de processamento em filas de alta e baixa prioridade para garantir que as mensagens são processadas nas taxas esperadas.Monitor the processing speed on high and low priority queues to ensure that messages in these queues are processed at the expected rates.

Se precisar de garantir que as mensagens de baixa prioridade vão ser processadas, será necessário implementar a abordagem de várias filas de mensagens com vários conjuntos de consumidores.If you need to guarantee that low priority messages will be processed, it's necessary to implement the multiple message queue approach with multiple pools of consumers. Em alternativa, numa fila que suporte a priorização das mensagens, é possível aumentar dinamicamente a prioridade de uma mensagem em fila de acordo com a sua antiguidade.Alternatively, in a queue that supports message prioritization, it's possible to dynamically increase the priority of a queued message as it ages. No entanto, esta abordagem depende da fila de mensagens que fornece esta funcionalidade.However, this approach depends on the message queue providing this feature.

A utilização de uma fila separada para cada prioridade de mensagem funciona melhor em sistemas com um pequeno número de prioridades bem definidas.Using a separate queue for each message priority works best for systems that have a small number of well-defined priorities.

As prioridades das mensagens podem ser determinadas logicamente pelo sistema.Message priorities can be determined logically by the system. Por exemplo, em vez de ter mensagens com alta e baixa prioridade explícita, estas podem ser designadas como “cliente pago” ou “cliente gratuito”.For example, rather than having explicit high and low priority messages, they could be designated as “fee paying customer,” or “non-fee paying customer.” Dependendo do seu modelo de negócio, o sistema pode alocar mais recursos ao processamento de mensagens de clientes pagos do que aos clientes gratuitos.Depending on your business model, your system can allocate more resources to processing messages from fee paying customers than non-fee paying ones.

Pode haver um custo financeiro e processual associado à verificação de uma mensagem numa fila (alguns sistemas de mensagens comerciais cobram uma pequena taxa sempre que uma mensagem é publicada ou obtida e sempre que uma fila é consultada relativamente a mensagens).There might be a financial and processing cost associated with checking a queue for a message (some commercial messaging systems charge a small fee each time a message is posted or retrieved, and each time a queue is queried for messages). Este custo aumenta com a verificação de várias filas.This cost increases when checking multiple queues.

É possível ajustar dinamicamente o tamanho de um conjunto de consumidores com base no comprimento da fila na qual o conjunto está a trabalhar.It's possible to dynamically adjust the size of a pool of consumers based on the length of the queue that the pool is servicing. Para obter mais informações, veja a Orientações sobre o Dimensionamento Automático.For more information, see the Autoscaling Guidance.

Quando utilizar este padrãoWhen to use this pattern

Este padrão é prático em cenários onde:This pattern is useful in scenarios where:

  • O sistema tem de processar várias tarefas com diferentes prioridades.The system must handle multiple tasks that have different priorities.

  • Os utilizadores ou inquilinos diferentes devem ser fornecidos com uma prioridade diferente.Different users or tenants should be served with different priority.

ExemploExample

O Microsoft Azure não fornece um mecanismo de colocação em fila que suporta nativamente uma priorização automática de mensagens através da ordenação.Microsoft Azure doesn't provide a queuing mechanism that natively supports automatic prioritization of messages through sorting. No entanto, fornece tópicos e subscrições do Azure Service Bus que suportam um mecanismo de colocação em fila que fornece a filtragem de mensagens, juntamente com uma vasta gama de capacidades flexíveis que o tornam ideal para utilização na maioria das implementações de fila de prioridade.However, it does provide Azure Service Bus topics and subscriptions that support a queuing mechanism that provides message filtering, together with a wide range of flexible capabilities that make it ideal for use in most priority queue implementations.

Uma solução do Azure pode implementar um tópico do Azure Service Bus no qual uma aplicação pode publicar mensagens, da mesma forma que uma fila.An Azure solution can implement a Service Bus topic an application can post messages to, in the same way as a queue. As mensagens podem conter metadados sob a forma de propriedades personalizadas definidas pela aplicação.Messages can contain metadata in the form of application-defined custom properties. As subscrições do Service Bus podem ser associadas ao tópico e podem igualmente filtrar as mensagens com base nas respetivas propriedades.Service Bus subscriptions can be associated with the topic, and these subscriptions can filter messages based on their properties. Quando uma aplicação envia uma mensagem para um tópico, esta é direcionada para a subscrição adequada, onde pode ser lida por um consumidor.When an application sends a message to a topic, the message is directed to the appropriate subscription where it can be read by a consumer. Os processos do consumidor podem obter mensagens de uma subscrição com a mesma semântica que uma fila de mensagens (uma subscrição é uma fila lógica).Consumer processes can retrieve messages from a subscription using the same semantics as a message queue (a subscription is a logical queue). A figura seguinte ilustra a implementação de uma fila de prioridade com tópicos e subscrições do Azure Service Bus.The following figure illustrates implementing a priority queue with Azure Service Bus topics and subscriptions.

Figura 3 – Implementação de uma fila de prioridade com tópicos e subscrições do Azure Service Bus

Na figura acima, a aplicação cria várias mensagens e atribui uma propriedade personalizada denominada Priority em cada mensagem com um valor, High ou Low.In the figure above, the application creates several messages and assigns a custom property called Priority in each message with a value, either High or Low. A aplicação publica estas mensagens num tópico.The application posts these messages to a topic. O tópico tem duas subscrições associadas, as quais filtram as mensagens ao examinarem a propriedade Priority.The topic has two associated subscriptions that both filter messages by examining the Priority property. Uma subscrição aceita mensagens onde a propriedade Priority está definida como High e a outra aceita mensagens onde a propriedade Priority está definida como Low.One subscription accepts messages where the Priority property is set to High, and the other accepts messages where the Priority property is set to Low. Um conjunto de consumidores lê mensagens de cada subscrição.A pool of consumers reads messages from each subscription. A subscrição de alta prioridade tem um conjunto maior e estes consumidores podem estar a ser executados em computadores mais poderosos com mais recursos disponíveis do que os consumidores no agrupamento de baixa prioridade.The high priority subscription has a larger pool, and these consumers might be running on more powerful computers with more resources available than the consumers in the low priority pool.

Tenha em atenção que não há nada de especial sobre a designação de mensagens de alta e baixa prioridade neste exemplo.Note that there's nothing special about the designation of high and low priority messages in this example. São apenas etiquetas especificadas como propriedades em cada mensagem e são utilizadas para direcionar as mensagens para uma subscrição específica.They're simply labels specified as properties in each message, and are used to direct messages to a specific subscription. Se forem precisas prioridades adicionais, será relativamente fácil criar mais subscrições e conjuntos de processos de consumidor para processar estas prioridades.If additional priorities are required, it's relatively easy to create further subscriptions and pools of consumer processes to handle these priorities.

A solução PriorityQueue disponível no GitHub contém uma implementação desta abordagem.The PriorityQueue solution available on GitHub contains an implementation of this approach. Esta solução contém duas funções de trabalho com o nome PriorityQueue.High e PriorityQueue.Low.This solution contains two worker role projects named PriorityQueue.High and PriorityQueue.Low. Estas funções de trabalho herdam a classe PriorityWorkerRole que contém a funcionalidade para ligar a uma subscrição especificada no método OnStart.These worker roles inherit from the PriorityWorkerRole class that contains the functionality for connecting to a specified subscription in the OnStart method.

As funções de trabalho PriorityQueue.High e PriorityQueue.Low ligam-se a subscrições diferentes, definidas pelas respetivas definições de configuração.The PriorityQueue.High and PriorityQueue.Low worker roles connect to different subscriptions, defined by their configuration settings. Um administrador pode configurar diferentes números de cada função a ser executada.An administrator can configure different numbers of each role to be run. Normalmente, existem mais instâncias da função de trabalho PriorityQueue.High do que da função de trabalho PriorityQueue.Low.Typically there'll be more instances of the PriorityQueue.High worker role than the PriorityQueue.Low worker role.

O método Run na classe PriorityWorkerRole faz com que o método virtual ProcessMessage (também definido na classe PriorityWorkerRole) seja executado para cada mensagem recebida na fila.The Run method in the PriorityWorkerRole class arranges for the virtual ProcessMessage method (also defined in the PriorityWorkerRole class) to be run for each message received on the queue. O código seguinte mostra os métodos Run e ProcessMessage.The following code shows the Run and ProcessMessage methods. A classe QueueManager, definida no projeto PriorityQueue.Shared, fornece métodos do programa auxiliar para utilizar as filas do Azure Service Bus.The QueueManager class, defined in the PriorityQueue.Shared project, provides helper methods for using Azure Service Bus queues.

public class PriorityWorkerRole : RoleEntryPoint
{
  private QueueManager queueManager;
  ...

  public override void Run()
  {
    // Start listening for messages on the subscription.
    var subscriptionName = CloudConfigurationManager.GetSetting("SubscriptionName");
    this.queueManager.ReceiveMessages(subscriptionName, this.ProcessMessage);
    ...;
  }
  ...

  protected virtual async Task ProcessMessage(BrokeredMessage message)
  {
    // Simulating processing.
    await Task.Delay(TimeSpan.FromSeconds(2));
  }
}

Ambas as funções de trabalho PriorityQueue.High e PriorityQueue.Low substituem a funcionalidade predefinida do método ProcessMessage.The PriorityQueue.High and PriorityQueue.Low worker roles both override the default functionality of the ProcessMessage method. O código abaixo mostra o método ProcessMessage para a função de trabalho PriorityQueue.High.The code below shows the ProcessMessage method for the PriorityQueue.High worker role.

protected override async Task ProcessMessage(BrokeredMessage message)
{
  // Simulate message processing for High priority messages.
  await base.ProcessMessage(message);
  Trace.TraceInformation("High priority message processed by " +
    RoleEnvironment.CurrentRoleInstance.Id + " MessageId: " + message.MessageId);
}

Quando uma aplicação publica mensagens no tópico associado às subscrições utilizadas pelas funções de trabalho PriorityQueue.High e PriorityQueue.Low, esta especifica a prioridade com a propriedade personalizada Priority, conforme mostrado no exemplo de código seguinte.When an application posts messages to the topic associated with the subscriptions used by the PriorityQueue.High and PriorityQueue.Low worker roles, it specifies the priority by using the Priority custom property, as shown in the following code example. Este código (implementado na classe WorkerRole no projeto PriorityQueue.Sender), utiliza o método do programa auxiliar SendBatchAsync da classe QueueManager para publicar mensagens num tópico em lotes.This code (implemented in the WorkerRole class in the PriorityQueue.Sender project), uses the SendBatchAsync helper method of the QueueManager class to post messages to a topic in batches.

// Send a low priority batch.
var lowMessages = new List<BrokeredMessage>();

for (int i = 0; i < 10; i++)
{
  var message = new BrokeredMessage() { MessageId = Guid.NewGuid().ToString() };
  message.Properties["Priority"] = Priority.Low;
  lowMessages.Add(message);
}

this.queueManager.SendBatchAsync(lowMessages).Wait();
...

// Send a high priority batch.
var highMessages = new List<BrokeredMessage>();

for (int i = 0; i < 10; i++)
{
  var message = new BrokeredMessage() { MessageId = Guid.NewGuid().ToString() };
  message.Properties["Priority"] = Priority.High;
  highMessages.Add(message);
}

this.queueManager.SendBatchAsync(highMessages).Wait();

Os padrões e orientações que se seguem também podem ser relevantes ao implementar este padrão:The following patterns and guidance might also be relevant when implementing this pattern:

  • Um exemplo que demonstra este padrão está disponível no GitHub.A sample that demonstrates this pattern is available on GitHub.

  • Asynchronous Messaging Primer (Manual Básico de Mensagens Assíncronas).Asynchronous Messaging Primer. Um serviço de consumidor que processa um pedido pode precisar de enviar uma resposta para a instância da aplicação que publicou o pedido.A consumer service that processes a request might need to send a reply to the instance of the application that posted the request. Fornece informações sobre as estratégias que pode utilizar para implementar mensagens de pedido/resposta.Provides information on the strategies that you can use to implement request/response messaging.

  • Padrão de Consumidores Concorrentes.Competing Consumers pattern. Para aumentar o débito das filas, é possível ter vários consumidores à escuta na mesma fila e processar as tarefas em paralelo.To increase the throughput of the queues, it’s possible to have multiple consumers that listen on the same queue, and process the tasks in parallel. Estes consumidores vão competir pelas mensagens, mas apenas um pode processar cada mensagem.These consumers will compete for messages, but only one should be able to process each message. Fornece mais informações sobre os benefícios e compromissos da implementação desta abordagem.Provides more information on the benefits and tradeoffs of implementing this approach.

  • Padrão de Limitação.Throttling pattern. Pode implementar a limitação com filas.You can implement throttling by using queues. As mensagens de prioridade podem ser utilizadas para garantir que os pedidos de aplicações críticas, ou aplicações a serem executadas por clientes de elevado valor, têm prioridade sobre os pedidos de aplicações menos importantes.Priority messaging can be used to ensure that requests from critical applications, or applications being run by high-value customers, are given priority over requests from less important applications.

  • Orientações de Dimensionamento Automático.Autoscaling Guidance. Pode ser possível dimensionar o tamanho do conjunto dos processos de consumidor a processar uma fila consoante o comprimento da fila.It might be possible to scale the size of the pool of consumer processes handling a queue depending on the length of the queue. Esta estratégia pode ajudar a melhorar o desempenho, especialmente para conjuntos a processar mensagens de alta prioridade.This strategy can help to improve performance, especially for pools handling high priority messages.

  • Enterprise Integration Patterns with Service Bus (Padrões de Enterprise Integration com o Service Bus) no blogue de Abhishek Lal.Enterprise Integration Patterns with Service Bus on Abhishek Lal’s blog.