Filas e tópicos particionados

O Barramento de Serviço do Azure emprega vários agentes de mensagens para processar mensagens e vários armazenamentos de mensagens para armazenar mensagens. Uma fila ou tópico convencional é manipulado por um único agente de mensagens e armazenado em um armazenamento de mensagens. As partições do Barramento de Serviço permitem que filas e tópicos, ou entidades de mensagens, sejam particionados em vários agentes de mensagens e armazenamentos de mensagens. O particionamento significa que a taxa de transferência geral de uma entidade particionada não é mais limitada pelo desempenho de um único agente de mensagens ou armazenamento de mensagens. Além disso, uma interrupção temporária de um armazenamento de mensagens não torna uma fila ou tópico particionado indisponível. Filas e tópicos particionados podem conter todos os recursos avançados do Service Bus, como suporte para transações e sessões.

Nota

Existem algumas diferenças entre o Basic / Standard e Premium SKU quando se trata de particionamento.

  • O particionamento está disponível na criação de entidades para todas as filas e tópicos em SKUs Básico ou Padrão. Um namespace pode ter entidades particionadas e não particionadas.
  • O particionamento está disponível na criação de namespace para a SKU de mensagens Premium, e todas as filas e tópicos nesse namespace serão particionados. Todas as entidades particionadas migradas anteriormente em namespaces Premium continuarão a funcionar conforme o esperado.
  • Quando o particionamento está ativado nas SKUs Básica ou Padrão, sempre criaremos 16 partições.
  • Quando o particionamento está habilitado no SKU Premium, a quantidade de partições é especificada durante a criação do namespace.

Não é possível alterar a opção de particionamento em qualquer namespace, fila ou tópico existente; Você só pode definir a opção quando criar a entidade.

Como funciona

Cada fila ou tópico particionado consiste em várias partições. Cada partição é armazenada em um armazenamento de mensagens diferente e manipulada por um agente de mensagens diferente. Quando uma mensagem é enviada para uma fila ou tópico particionado, o Service Bus atribui a mensagem a uma das partições. A seleção é feita aleatoriamente pelo Service Bus ou usando uma chave de partição que o remetente pode especificar.

Quando um cliente deseja receber uma mensagem de uma fila particionada ou de uma assinatura para um tópico particionado, o Service Bus consulta todas as partições para mensagens e, em seguida, retorna a primeira mensagem obtida de qualquer um dos armazenamentos de mensagens para o destinatário. O Barramento de Serviço armazena em cache as outras mensagens e as retorna quando recebe mais solicitações de recebimento. Um cliente recetor não está ciente do particionamento; O comportamento voltado para o cliente de uma fila ou tópico particionado (por exemplo, Read, Complete, Defer, Deadletter, Prefetching) é idêntico ao comportamento de uma entidade regular.

A operação de visualização em uma entidade não particionada sempre retorna a mensagem mais antiga, mas não em uma entidade particionada. Em vez disso, ele retorna a mensagem mais antiga em uma das partições cujo agente de mensagens respondeu primeiro. Não há garantia de que a mensagem retornada seja a mais antiga em todas as partições.

Não há custo extra ao enviar ou receber uma mensagem de uma fila ou tópico particionado.

Nota

A operação peek retorna a mensagem mais antiga da partição com base em seu número de sequência. Para entidades particionadas, o número de sequência é emitido em relação à partição. Para obter mais informações, consulte Sequenciamento de mensagens e carimbos de data/hora.

Utilização de chaves de partição

Quando uma mensagem é enfileirada em uma fila ou tópico particionado, o Barramento de Serviço verifica a presença de uma chave de partição. Se encontrar uma, seleciona a partição com base nessa chave. Se não encontrar uma chave de partição, seleciona a partição com base num algoritmo interno.

Usando uma chave de partição

Alguns cenários, como sessões ou transações, exigem que as mensagens sejam armazenadas em uma partição específica. Todos esses cenários exigem o uso de uma chave de partição. Todas as mensagens que usam a mesma chave de partição são atribuídas à mesma partição. Se a partição estiver temporariamente indisponível, o Service Bus retornará um erro.

Dependendo do cenário, diferentes propriedades de mensagem são usadas como uma chave de partição:

SessionId: Se uma mensagem tiver a propriedade ID da sessão definida, o Service Bus a usará como a chave de partição. Dessa forma, todas as mensagens que pertencem à mesma sessão são tratadas pelo mesmo agente de mensagens. As sessões permitem que o Service Bus garanta a ordenação das mensagens, bem como a consistência dos estados da sessão.

PartitionKey: Se uma mensagem tiver a propriedade da chave de partição, mas não a propriedade ID da sessão definida, o Service Bus usará o valor da propriedade da chave de partição como a chave de partição. Se a mensagem tiver o ID da sessão e as propriedades da chave de partição definidas, ambas as propriedades deverão ser idênticas. Se a propriedade da chave de partição estiver definida como um valor diferente da propriedade ID da sessão, o Barramento de Serviço retornará uma exceção de operação inválida. A propriedade da chave de partição deve ser usada se um remetente enviar mensagens transacionais sem reconhecimento de sessão. A chave de partição garante que todas as mensagens enviadas dentro de uma transação sejam tratadas pelo mesmo agente de mensagens.

MessageId: Se a fila ou tópico foi criado com o recurso de deteção de duplicados e as propriedades de ID de sessão ou chave de partição não estão definidas, o valor da propriedade ID da mensagem serve como a chave de partição. (As bibliotecas de cliente da Microsoft atribuem automaticamente um ID de mensagem se o aplicativo de envio não o fizer.) Nesse caso, todas as cópias da mesma mensagem são manipuladas pelo mesmo agente de mensagens. Essa ID permite que o Service Bus detete e elimine mensagens duplicadas. Se o recurso de deteção de duplicados não estiver habilitado, o Service Bus não considerará a propriedade ID da mensagem como uma chave de partição.

Não usar uma chave de partição

Na ausência de uma chave de partição, o Service Bus distribui mensagens de forma round-robin para todas as partições da fila ou tópico particionado. Se a partição escolhida não estiver disponível, o Service Bus atribuirá a mensagem a uma partição diferente. Dessa forma, a operação de envio é bem-sucedida apesar da indisponibilidade temporária de um armazenamento de mensagens. No entanto, você não conseguirá a ordem garantida que uma chave de partição fornece.

Para obter uma discussão mais aprofundada sobre a compensação entre disponibilidade (sem chave de partição) e consistência (usando uma chave de partição), consulte Disponibilidade e consistência em Hubs de Eventos. Exceto para o ID de partição não ser exposto aos usuários, essas informações se aplicam igualmente a entidades particionadas do Service Bus.

Para dar ao Service Bus tempo suficiente para enfileirar a mensagem em uma partição diferente, o valor de tempo limite especificado pelo cliente que envia a mensagem deve ser maior que 15 segundos. O valor padrão de 60 segundos é recomendado.

Uma chave de partição "fixa" uma mensagem a uma partição específica. Se o armazenamento de mensagens que contém essa partição não estiver disponível, o Service Bus retornará um erro. Na ausência de uma chave de partição, o Service Bus pode escolher uma partição diferente e a operação é bem-sucedida. Portanto, é recomendável que você não forneça uma chave de partição, a menos que seja necessário.

Tópicos avançados

Usar transações com entidades particionadas

As mensagens que são enviadas como parte de uma transação têm de especificar uma chave de partição. A chave pode ser uma das seguintes propriedades: ID da sessão, chave de partição ou ID da mensagem. Todas as mensagens enviadas como parte da mesma transação devem especificar a mesma chave de partição. Se você tentar enviar uma mensagem sem uma chave de partição dentro de uma transação, o Service Bus retornará uma exceção de operação inválida. Se você tentar enviar várias mensagens dentro da mesma transação que tenham chaves de partição diferentes, o Service Bus retornará uma exceção de operação inválida. Por exemplo:

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();

Se qualquer uma das propriedades que servem como uma chave de partição estiver definida, o Service Bus fixará a mensagem em uma partição específica. Esse comportamento ocorre se uma transação é usada ou não. É recomendável que você não especifique uma chave de partição se ela não for necessária.

Usar transações em sessões com entidades particionadas

Para enviar uma mensagem transacional para um tópico ou fila com reconhecimento de sessão, a mensagem deve ter a propriedade ID da sessão definida. Se a propriedade da chave de partição também for especificada, ela deverá ser idêntica à propriedade ID da sessão. Se forem diferentes, o Service Bus retornará uma exceção de operação inválida.

Ao contrário de filas ou tópicos regulares (não particionados), não é possível usar uma única transação para enviar várias mensagens para sessões diferentes. Se tentado, o Service Bus retorna uma exceção de operação inválida. Por exemplo:

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();

Reencaminhamento automático de mensagens com entidades particionadas

O Service Bus oferece suporte ao encaminhamento automático de mensagens de, para ou entre entidades particionadas. Você pode habilitar esse recurso ao criar ou atualizar filas e assinaturas. Para obter mais informações, consulte Habilitar o encaminhamento de mensagens. Se a mensagem especificar uma chave de partição (ID de sessão, chave de partição ou ID de mensagem), essa chave de partição será usada para a entidade de destino.

Considerações e orientações

  • Recursos de alta consistência: se uma entidade usa recursos como sessões, deteção de duplicados ou controle explícito de chave de particionamento, as operações de mensagens são sempre roteadas para uma partição específica. Se qualquer uma das partições tiver alto tráfego ou o armazenamento subjacente não estiver íntegro, essas operações falharão e a disponibilidade será reduzida. No geral, a consistência ainda é muito maior do que as entidades não particionadas; Apenas um subconjunto de tráfego está enfrentando problemas, em oposição a todo o tráfego. Para obter mais informações, consulte esta discussão sobre disponibilidade e consistência.
  • Gerenciamento: Operações como Criar, Atualizar e Excluir devem ser executadas em todas as partições da entidade. Se alguma partição não estiver íntegra, isso pode resultar em falhas para essas operações. Para a operação Get, informações como contagens de mensagens devem ser agregadas de todas as partições. Se alguma partição não estiver íntegra, o status de disponibilidade da entidade será relatado como limitado.
  • Cenários de mensagens de baixo volume: Para esses cenários, especialmente ao usar o protocolo HTTP, talvez seja necessário executar várias operações de recebimento para obter todas as mensagens. Para solicitações de recebimento, o front-end executa um recebimento em todas as partições e armazena em cache todas as respostas recebidas. Uma solicitação de recebimento subsequente na mesma conexão se beneficiaria desse cache e as latências de recebimento seriam menores. No entanto, se você tiver várias conexões ou usar HTTP, uma nova conexão será estabelecida para cada solicitação. Como tal, não há garantia de que ele pousará no mesmo nó. Se todas as mensagens existentes estiverem bloqueadas e armazenadas em cache em outro front-end, a operação de recebimento retornará null. As mensagens eventualmente expiram e você pode recebê-las novamente. HTTP keep-alive é recomendado. Ao usar o particionamento em cenários de baixo volume, as operações de recebimento podem levar mais tempo do que o esperado. Portanto, recomendamos que você não use particionamento nesses cenários. Exclua todas as entidades particionadas existentes e recrie-as com o particionamento desativado para melhorar o desempenho.
  • Procurar/Espreitar mensagens: A operação de pré-visualização nem sempre devolve o número de mensagens solicitadas. Há duas razões comuns para esse comportamento. Uma razão é que o tamanho agregado da coleção de mensagens excede o tamanho máximo. Outra razão é que, em filas ou tópicos particionados, uma partição pode não ter mensagens suficientes para retornar o número solicitado de mensagens. Em geral, se um aplicativo quiser espiar/procurar um número específico de mensagens, ele deve chamar a operação de visualização repetidamente até obter esse número de mensagens, ou não há mais mensagens para espiar. Para obter mais informações, incluindo exemplos de código, consulte Navegação por mensagens.

Limitações de entidades particionadas

Atualmente, o Service Bus impõe as seguintes limitações em filas e tópicos particionados:

  • Para namespaces premium particionados, o tamanho da mensagem é limitado a 1 MB quando as mensagens são enviadas individualmente e o tamanho do lote é limitado a 1 MB quando as mensagens são enviadas em lote.
  • Filas e tópicos particionados não suportam o envio de mensagens que pertencem a sessões diferentes em uma única transação.
  • Atualmente, o Service Bus permite até 100 filas particionadas ou tópicos por namespace para a SKU Básica e Padrão. Cada fila ou tópico particionado conta para a cota de 10.000 entidades por namespace.

Próximos passos

Você pode habilitar o particionamento usando o portal do Azure, PowerShell, CLI, modelo do Gerenciador de Recursos, .NET, Java, Python e JavaScript. Para obter mais informações, consulte Habilitar particionamento (básico / padrão).

Leia sobre os principais conceitos da especificação de mensagens AMQP (Advanced Message Queueing Protocol) 1.0 no guia de protocolo AMQP 1.0.