Filas e tópicos particionados

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

Observação

Há algumas diferenças entre o SKU Básico/Standard e Premium quando se trata de particionamento.

  • Particionar está disponível na criação da identidade para todas as filas e tópicos em SKUs Básico ou Standard. Um namespace pode ter entidades particionadas e não particionadas.
  • O particionamento está disponível na criação de namespaces para a SKU de mensagens Premium, e todas as filas e tópicos nesse namespace serão particionados. Qualquer entidade particionada migrada existente anteriormente nos namespaces Premium continuará a funcionar como esperado.
  • Quando o particionamento estiver habilitado nos SKUs Básico ou Standard, sempre criaremos 16 partições.
  • Quando o particionamento é 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 um namespace, fila ou tópico existente; você pode definir a opção apenas quando cria a entidade.

Como ele funciona

Cada fila ou tópico particionado consiste em várias partições. Cada partição é armazenada em um repositório de mensagens diferente e processada por um agente de mensagens diferente. Quando uma mensagem é enviada a uma fila ou um tópico particionado, o Barramento de Serviço atribui a mensagem a uma das partições. A seleção é feita aleatoriamente pelo Barramento de Serviço ou por uma chave de partição que pode ser especificada pelo remetente.

Quando um cliente deseja receber uma mensagem de uma fila particionada ou de uma assinatura de um tópico particionado, o Barramento de Serviço consulta todas as partições em busca de mensagens e, em seguida, exibe a primeira mensagem obtida de qualquer um dos repositórios de mensagens para o destinatário. O Barramento de Serviço armazena em cache as outras mensagens e as retorna ao receber mais solicitações de recebimento. Um cliente receptor não está ciente do particionamento; o comportamento voltado para o cliente de uma fila ou um tópico particionado (por exemplo, ler, concluir, adiar, colocar mensagem na fila de mensagens mortas, executar pré-busca) é idêntico ao comportamento de uma entidade regular.

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

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

Observação

A operação de inspeção exibe a mensagem mais antiga da partição com base no número sequencial dela. Para entidades particionadas, o número da sequência é emitido com relação à partição. Para mais informações, confira Sequenciamento e registros de data e hora das mensagens.

Uso de chaves de partição

Quando uma mensagem é enfileirada em uma fila ou um tópico particionado, o Barramento de Serviço verifica a presença de uma chave de partição. Se ele encontrar uma chave, escolherá a partição com base nela. Se ele não encontrar uma chave de partição, escolherá a partição com base em um 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 Barramento de Serviço exibirá um erro.

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

SessionId: caso uma mensagem tenha a propriedade de ID da sessão definida, o Barramento de Serviço a usará como a chave de partição. Dessa forma, todas as mensagens que pertencem à mesma sessão são manipuladas pelo mesmo agente de mensagens. Sessões habilitam o Barramento de Serviço a garantir a ordenação das mensagens, bem como a consistência dos estados de sessão.

PartitionKey: caso uma mensagem tenha a propriedade da chave de partição definida, mas não a propriedade de ID da sessão, o Barramento de Serviço usará o valor da propriedade da chave de partição como a chave de partição. Caso a mensagem tenha as propriedades de ID da sessão e da chave de partição definidas, as propriedades deverão ser idênticas. Se a propriedade da chave de partição estiver definida com um valor diferente da propriedade de ID da sessão, o Barramento de Serviço retornará uma exceção de operação inválida. A propriedade de Chave de partição deverá ser usada caso um remetente envie mensagens transacionais sem reconhecimento de sessão. A chave de partição garante que todas as mensagens enviadas em uma transação sejam manipuladas pelo mesmo agente de mensagens.

MessageId: se a fila ou o tópico foi criado com o recurso de detecção de duplicidades e a ID da sessão ou as propriedades da chave de partição não estiverem definidas, o valor da propriedade ID da mensagem servirá como a chave de partição. (As bibliotecas de cliente Microsoft atribuirão automaticamente uma ID de mensagem se o aplicativo de envio não fizer isso). Nesse caso, todas as cópias da mesma mensagem são processadas pelo mesmo agente de mensagens. Este ID permite que o Barramento de Serviço detecte e elimine mensagens duplicadas. Se o recurso de detecção de duplicidades não estiver habilitado, o Barramento de Serviço não considerará a propriedade ID da mensagem como uma chave de partição.

Não usando uma chave de partição

Na ausência de uma chave de partição, o Barramento de Serviço distribui mensagens em forma de round robin para todas as partições da fila ou do tópico particionado. Se a partição escolhida não estiver disponível, o Barramento de Serviço atribuirá a mensagem a uma partição diferente. Dessa forma, a operação de envio será bem-sucedida independentemente da indisponibilidade temporária de um repositório de mensagens. No entanto, você não obterá a ordenação garantida que uma chave de partição oferece.

Para obter uma discussão mais detalhada sobre a compensação entre disponibilidade (sem chave de partição) e consistência (usando uma chave de partição), confira Disponibilidade e consistência no Hubs de Eventos. Exceto que a ID de partição não esteja sendo exposta aos usuários, essas informações se aplicam igualmente a entidades de Barramento de Serviço particionadas.

Para dar ao Barramento de Serviço tempo suficiente para enfileirar a mensagem em uma partição diferente, o valor de tempo de 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 em uma partição específica. Se o repositório de mensagens que mantém essa partição estiver indisponível, o Barramento de Serviço exibirá um erro. Na ausência de uma chave de partição, o Barramento de Serviço pode escolher uma partição diferente e a operação será bem-sucedida. Portanto, é recomendável que você não forneça uma chave de partição, a menos que ela seja solicitada.

Tópicos avançados

Usar transações com entidades particionadas

As mensagens enviadas como parte de uma transação devem 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 que são enviadas como parte da mesma transação devem especificar a mesma chave de partição. Caso você tente enviar uma mensagem sem uma chave de partição em uma transação, o Barramento de Serviço retornará uma exceção de operação inválida. Caso você tente enviar várias mensagens que tenham chaves de partição diferentes na mesma transação, o Barramento de Serviço 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 alguma das propriedades que servem como uma chave de partição for definida, o Barramento de Serviço fixará a mensagem em uma partição específica. Esse comportamento ocorre quer uma transação seja usada ou não. É recomendável que você não especifique uma chave de partição se isso não for necessário.

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

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

Diferentemente de filas ou tópicos regulares (não particionados), não é possível usar uma única transação para enviar várias mensagens a sessões diferentes. Se você tentar fazer isso, o Barramento de Serviço 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.SessionId = "mySession";
    await sender.SendMessageAsync(msg); 
    ts.Complete();
}
committableTransaction.Commit();

Encaminhamento automático de mensagens com entidades particionadas

O Barramento de Serviço dá 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 saber mais, confira Habilitar encaminhamento de mensagens. Se a mensagem especificar uma chave de partição (ID da sessão, chave de partição ou ID da mensagem), ela será usada para a entidade de destino.

Considerações e diretrizes

  • Recursos de alta consistência: se uma entidade usar recursos como sessões, detecção de duplicidades ou controle explícito de chaves de particionamento, as operações de mensagens serão sempre roteadas para uma partição específica. Se alguma das partições apresentar alto tráfego ou se o repositório subjacente não estiver íntegro, essas operações apresentarão falha e a disponibilidade será reduzida. Em geral, a consistência ainda é muito maior do que em entidades não particionadas; somente um subconjunto de tráfego tem problemas, em vez de 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 poderá resultar na falha dessas operações. Para a operação Get, informações como números 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á informado como limitado.
  • Cenários de mensagens de baixo volume: para esses cenários, particularmente ao usar o protocolo HTTP, talvez você precise executar várias operações de recebimento para obter todas as mensagens. Para solicitações de recebimento, o front-end realiza 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 beneficiará desse armazenamento em cache, e as latências de recebimento são menores. No entanto, se você tiver várias conexões ou se usar HTTP, uma nova conexão será estabelecida para cada solicitação. Assim, não há garantia de que ela chegará ao mesmo nó. Se todas as mensagens existentes forem bloqueadas e armazenadas em cache no outro front-end, a operação de recebimento resultará em nulo. As mensagens eventualmente expiram e você pode recebê-las novamente. O keep-alive de HTTP é recomendável. Ao usar o particionamento em cenários de baixo volume, as operações de recebimento podem demorar mais tempo que o esperado. Portanto, não recomendamos o uso de particionamento nesses cenários. Exclua todas as entidades particionadas existentes e recrie-as com o particionamento desabilitado para melhorar o desempenho.
  • Procurar/espiar mensagens: a operação de espiar nem sempre retorna o número de mensagens solicitado. Há duas razões comuns para este comportamento. Uma razão é que o tamanho agregado da coleção de mensagens excede o tamanho máximo. Outro motivo é 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 procurar/espiar um número específico de mensagens, ele deverá solicitar a operação de espiar repetidamente até obter o número de mensagens ou até não existirem mais mensagens para espiar. Para saber mais, incluindo exemplos de código, confira Navegação de mensagens.

Limitações das entidades particionadas

Atualmente, o Barramento de Serviço impõe as seguintes limitações a 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 um lote.
  • Filas e tópicos particionados não dão suporte ao envio de mensagens que pertencem a sessões diferentes em uma única transação.
  • O Barramento de Serviço atualmente permite até 100 filas ou tópicos particionados por namespace para o SKU Básico e Standard. Cada fila ou tópico particionado conta para a cota de 10.000 entidades por namespace.

Próximas etapas

Você pode habilitar o particionamento usando o portal do Azure, o PowerShell, a CLI, modelo do ARM, o .NET, o Java, o Python e o JavaScript. Para saber mais, confira Habilitar o particionamento (Básico / Standard).

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