Exportar (0) Imprimir
Expandir Tudo

Filas, tópicos e assinaturas do Service Bus

Atualizado: abril de 2014

O Microsoft Azure Service Bus suporta um conjunto de tecnologias middleware orientadas a mensagens, baseadas em nuvem, incluindo filas confiáveis de mensagens e sistema durável de mensagens de publicação/assinatura. Tais recursos agenciados de mensagens podem ser considerados assíncronos ou recursos desacoplados de mensagens compatíveis com cenários de balanceamento de carga, desacoplamento temporal e publicação/assinatura usando a malha do sistema de mensagens do Service Bus. A comunicação desacoplada tem muitas vantagens; por exemplo, clientes e servidores podem se conectar conforme necessário e realizar suas operações de forma assíncrona.

Os padrões de sistema de mensagens que formam a base dos novos recursos de sistema de mensagens agenciado no Service Bus são Filas, Tópicos/Assinaturas e Regras/Ações.

As filas oferecem a entrega de mensagens do tipo Primeira a entrar, primeira a sair (FIFO) para um ou mais consumidores concorrentes. Ou seja, espera-se normalmente que as mensagens sejam recebidas e processadas pelos receptores na ordem temporal em que foram adicionadas, e cada mensagem será recebida e processada por somente um consumidor de mensagem. Um benefício principal de usar filas é obter o "desacoplamento temporal" dos componentes do aplicativo. Em outras palavras, os produtores (remetentes) e consumidores (receptores) não precisam enviar e receber mensagens ao mesmo tempo, pois as mensagens são armazenadas de forma duradoura na fila. Além disso, o produtor não precisa esperar uma resposta do consumidor para continuar a processar e enviar mensagens.

Um benefício relacionado é o "nivelamento de carga', que permite que produtores e consumidores enviem e recebam mensagens em diferentes taxas. Em muitos aplicativos, a carga do sistema varia com o passar do tempo. Entretanto, o tempo de processamento necessário para cada unidade de trabalho costuma ser constante. Intermediar produtores e consumidores de mensagens com uma fila significa que o aplicativo consumidor só precisa ser provisionado para ser capaz de lidar com cargas médias em vez de cargas de pico. A fila cresce e diminui de acordo com a variação da carga de entrada. Isso reduzirá os custos relacionados à quantidade de infraestrutura necessária para a manutenção da carga do aplicativo. Conforme a carga aumenta, mais processos de operadores podem ser adicionados para serem lidos a partir da fila. Cada mensagem é processada por apenas um dos processos de operador. Além do mais, esse balanceamento de carga baseado em recepção permite o uso aprimorado dos computadores dos operadores mesmo se eles forem diferentes quanto ao poder de processamento, pois receberão mensagens de acordo com suas próprias taxas máximas. Esse padrão costuma ser chamado de padrão do “consumidor concorrente”.

O uso de filas para intermediar produtores e consumidores de mensagens fornece um acoplamento flexível inerente entre os componentes. Devido aos produtores e consumidores não estarem atentos uns aos outros, um consumidor pode ser atualizado sem gerar nenhum efeito no produtor.

Criar uma fila é um processo de diversas etapas. As operações de gerenciamento para entidades de sistemas de mensagens do Service Bus (filas e tópicos) são realizadas através da classe Microsoft.ServiceBus.NamespaceManager, que é construída ao fornecer o endereço base do namespace do Service Bus e as credenciais do usuário. NamespaceManager fornece métodos para criar, enumerar e excluir entidades de sistemas de mensagens. Após criar um objeto Microsoft.ServiceBus.TokenProvider do nome do emissor e chave compartilhada, e um objeto de gerenciamento do namespace de serviço, é possível usar o método Microsoft.ServiceBus.NamespaceManager.CreateQueue(Microsoft.ServiceBus.Messaging.QueueDescription) para criar a fila. Por exemplo:

// Create management credentials
TokenProvider credentials = TokenProvider.CreateSharedSecretTokenProvider(IssuerName, IssuerKey);
// Create namespace client
namespaceManager namespaceClient = new namespaceManager(ServiceBusEnvironment.CreateServiceUri("sb", ServiceNamespace, string.Empty), credentials);

Em seguida, você pode criar um objeto de fila e uma fábrica de mensagens com o URI do Service Bus como argumento. Por exemplo:

QueueDescription myQueue;
myQueue = namespaceClient.CreateQueue("TestQueue");
MessagingFactory factory = MessagingFactory.Create(ServiceBusEnvironment.CreateServiceUri("sb", ServiceNamespace, string.Empty), credentials); 
QueueClient myQueueClient = factory.CreateQueueClient("TestQueue");

Então, será possível enviar mensagens para a fila. Por exemplo, se você tiver uma lista de mensagens agenciadas chamada MessageList, código será parecido com o seguinte:

for (int count = 0; count < 6; count++)
{
    var issue = MessageList[count];
    issue.Label = issue.Properties["IssueTitle"].ToString();
    myQueueClient.Send(issue);
}

É possível receber mensagens de uma fila, da seguinte forma:

while ((message = myQueueClient.Receive(new TimeSpan(hours: 0, minutes: 0, seconds: 5))) != null)
    {
        Console.WriteLine(string.Format("Message received: {0}, {1}, {2}", message.SequenceNumber, message.Label, message.MessageId));
        message.Complete();

        Console.WriteLine("Processing message (sleeping...)");
        Thread.Sleep(1000);
    }

No modo ReceiveAndDelete, a operação de recebimento é de disparo único, ou seja, quando Service Bus recebe a solicitação, ele marca a mensagem como sendo consumida e a retorna ao aplicativo. O modo ReceiveAndDelete é o modelo mais simples e funciona melhor para cenários em que o aplicativo permite o não processamento de uma mensagem em caso de falha. Para melhor entender isso, considere um cenário no qual o consumidor emite a solicitação de recebimento e, antes de processá-la, seu sistema falha. Como o Service Bus marca a mensagem como sendo consumida, quando o aplicativo for reiniciado e começar a consumir a mensagem novamente, ele terá perdido a mensagem que foi consumida antes da falha.

No modo PeekLock, a operação de recebimento se torna de dois estágios, o que torna possível suportar aplicativos que não consigam tolerar mensagens perdidas. Quando o Service Bus receber a solicitação, ele localizará a próxima mensagem a ser consumida, bloqueará essa mensagem para evitar que outros consumidores a recebam e depois a retornará ao aplicativo. Uma vez que o aplicativo tenha concluído o processamento da mensagem (ou a tenha armazenado de forma confiável para processamento futuro), ele concluirá a segunda etapa do processo de recebimento ao chamar Microsoft.ServiceBus.Messaging.BrokeredMessage.Complete na mensagem recebida. Quando o Service Bus detectar Complete, ele marcará a mensagem como sendo consumida.

Se o aplicativo não for capaz de processar a mensagem por algum motivo, ele chamará o método Microsoft.ServiceBus.Messaging.BrokeredMessage.Abandon na mensagem recebida (em vez de Complete). Isso permite que o Service Bus desbloqueie a mensagem e a disponibilize para ser recebida novamente, seja pelo mesmo consumidor ou por outro consumidor concorrente. Em segundo lugar, há um tempo limite associado ao bloqueio e, se o aplicativo não processar a mensagem antes de o tempo limite de bloqueio expirar (por exemplo, se o aplicativo sofrer uma falha), o Service Bus desbloqueará a mensagem e a disponibilizará para ser recebida novamente.

Caso o aplicativo sofra uma falha após o processamento da mensagem, mas antes da emissão da solicitação Complete, a mensagem será entregue novamente ao aplicativo quando ele for reiniciado. Isso geralmente é chamado de processamento Pelo menos uma vez, ou seja, cada mensagem é processada pelo menos uma vez. No entanto, em alguns casos, a mesma mensagem pode ser entregue novamente. Se o cenário não permitir o processamento de duplicatas, lógica adicional será necessária no aplicativo para detectar duplicatas, o que pode ser feito com a propriedade MessageId da mensagem, pois essa propriedade permanece inalterada entre as tentativas de entrega. Isso é conhecido como processamento “Apenas uma vez”.

Para obter mais informações e exemplos de trabalhos sobre como criar e enviar mensagens de e para filas, consulte o Tutorial do .NET do sistema de mensagens agenciado do Service Bus.

Diferentemente das filas, em que cada mensagem é processada por um único consumidor, os tópicos e as assinaturas oferecem um formato "um para muitos" de comunicação em um padrão "publicação/assinatura". Útil para dimensionar para um número muito grande de destinatários, cada mensagem publicada é disponibilizada para cada assinatura registrada com o tópico. As mensagens são enviadas para um tópico e entregues para uma ou mais assinaturas associadas, dependendo das regras de filtragem que podem ser definidas para cada uma das assinaturas. As assinaturas podem usar filtros adicionais para restringir as mensagens que desejam receber. As mensagens são enviadas para um tópico da mesma maneira que são enviadas para uma fila, mas não são recebidas diretamente do tópico. Em vez disso, elas são recebidas das assinaturas. Uma assinatura de tópico lembra uma fila virtual que recebe cópias das mensagens que são enviadas para o tópico. As mensagens são recebidas de uma assinatura exatamente da mesma maneira que são recebidas de uma fila.

Por meio de comparação, a funcionalidade de envio de mensagens de uma fila faz o mapeamento diretamente para um tópico e sua funcionalidade de recebimento de mensagens faz o mapeamento diretamente para uma assinatura. Entre outras coisas, isso significa que as assinaturas têm suporte aos mesmos padrões descritos anteriormente nessa seção no que diz respeito a filas: consumidor concorrente, desacoplamento temporal, nivelamento de carga e balanceamento de carga.

A criação de um tópico é semelhante à criação de uma fila, conforme mostrado no exemplo da seção anterior. Crie o serviço URI e use a classe NamespaceManager para criar o cliente do namespace. Então, será possível criar um tópico usando o método Microsoft.ServiceBus.NamespaceManager.CreateTopic(System.String). Por exemplo:

TopicDescription dataCollectionTopic = namespaceClient.CreateTopic("DataCollectionTopic");

A seguir, adicione assinaturas conforme desejado:

SubscriptionDescription myAgentSubscription = namespaceClient.CreateSubscription(myTopic.Path, "Inventory");
SubscriptionDescription myAuditSubscription = namespaceClient.CreateSubscription(myTopic.Path, "Dashboard");

Em seguida, crie um cliente de tópico. Por exemplo:

MessagingFactory factory = MessagingFactory.Create(serviceUri, tokenProvider);
TopicClient myTopicClient = factory.CreateTopicClient(myTopic.Path)

Usando o remetente da mensagem, é possível enviar e receber mensagens de e para um tópico, como mostrado na seção anterior. Por exemplo:

foreach (BrokeredMessage message in messageList)
{
    myTopicClient.Send(message);
    Console.WriteLine(
    string.Format("Message sent: Id = {0}, Body = {1}", message.MessageId, message.GetBody<string>()));
}

Semelhante às filas, as mensagens são recebidas a partir de uma assinatura usando um objeto SubscriptionClient em vez de um objeto QueueClient. Crie o cliente de assinatura, passando o nome do tópico, o nome da assinatura e (opcional) o modo de recebimento como parâmetros. Por exemplo, com a assinatura Inventário:

// Create the subscription client
MessagingFactory factory = MessagingFactory.Create(serviceUri, tokenProvider); 

SubscriptionClient agentSubscriptionClient = factory.CreateSubscriptionClient("IssueTrackingTopic", "Inventory", ReceiveMode.PeekLock);
SubscriptionClient auditSubscriptionClient = factory.CreateSubscriptionClient("IssueTrackingTopic", "Dashboard", ReceiveMode.ReceiveAndDelete); 

while ((message = agentSubscriptionClient.Receive(TimeSpan.FromSeconds(5))) != null)
{
    Console.WriteLine("\nReceiving message from Inventory...");
    Console.WriteLine(string.Format("Message received: Id = {0}, Body = {1}", message.MessageId, message.GetBody<string>()));
    message.Complete();
}          

// Create a receiver using ReceiveAndDelete mode
while ((message = auditSubscriptionClient.Receive(TimeSpan.FromSeconds(5))) != null)
{
    Console.WriteLine("\nReceiving message from Dashboard...");
    Console.WriteLine(string.Format("Message received: Id = {0}, Body = {1}", message.MessageId, message.GetBody<string>()));
}

ImportantImportante
Conforme observado no tópico Como: Publicar um serviço no registro do Service Bus, você pode usar Microsoft.ServiceBus.ServiceRegistrySettings para indicar se deseja que seu serviço possa ser detectado pelo Service Bus. Se o serviço for privado, somente indivíduos que saibam o URI específico poderão se conectar. Se for público, qualquer um poderá navegar pela hierarquia do Service Bus e encontrar o seu ouvinte. Entretanto, filas, tópicos e assinaturas não podem ser expostas através do registro do serviço.

Em muitos cenários, as mensagens que possuam características específicas precisam ser processadas de formas específicas. Para ativar esse recurso, é possível configurar as assinaturas para que encontrem mensagens que possuam propriedades desejáveis e, então, realizem determinadas modificações às propriedades. Embora o Service Bus detecte todas as mensagens enviadas ao tópico, só é possível copiar um subconjunto dessas mensagens para a fila de assinatura virtual. Isso pode ser feito usando os filtros de assinatura. Essas modificações são chamadas de ações de filtro. Quando uma assinatura é criada, você pode especificar uma expressão de filtro que opera nas propriedades da mensagem, tanto propriedades de sistema (por exemplo, Label) quanto propriedades de aplicativo, como StoreName no exemplo anterior. A expressão de filtro SQL é opcional nesse caso; sem uma expressão de filtro SQL, qualquer ação de filtro definida em uma assinatura será realizada em todas as mensagens daquela assinatura.

Usando o exemplo anterior, é possível criar a assinatura do Dashboard para filtrar mensagens que venham apenas da Store1 da seguinte maneira:

namespaceManager.CreateSubscription("IssueTrackingTopic", "Dashboard", new SqlFilter("StoreName = 'Store1'"));

Com esse filtro de assinatura ativo, somente mensagens com a propriedade StoreName definida como Store1 serão copiadas para a fila virtual da assinatura Dashboard.

Para ver os valores de filtro possíveis de Para obter mais informações sobre, consulte a documentação das classes Microsoft.ServiceBus.Messaging.SqlFilter e Microsoft.ServiceBus.Messaging.SqlRuleAction. Consulte também o exemplo Sistema de mensagens agenciado: filtros avançados sample.

Consulte também

Mostrar:
© 2014 Microsoft