Partilhar via


AMQP 1.0 no Guia de protocolo do Azure Service Bus e Hubs de Eventos

O Advanced Message Queueing Protocol 1.0 é um protocolo padronizado de enquadramento e transferência para transferência de mensagens de forma assíncrona, segura e confiável entre duas partes. É o protocolo principal do Azure Service Bus Messaging e dos Hubs de Eventos do Azure.

O AMQP 1.0 é o resultado de uma ampla colaboração do setor que reuniu fornecedores de middleware, como Microsoft e Red Hat, com muitos usuários de middleware de mensagens, como JP Morgan Chase, representando o setor de serviços financeiros. O fórum de normalização técnica para o protocolo AMQP e especificações de extensão é o OASIS, e obteve aprovação formal como norma internacional como ISO/IEC 19494:2014.

Objetivos

Este artigo resume os principais conceitos da especificação de mensagens AMQP 1.0 junto com as especificações de extensão desenvolvidas pelo Comitê Técnico do OASIS AMQP e explica como o Barramento de Serviço do Azure implementa e se baseia nessas especificações.

O objetivo é que qualquer desenvolvedor que use qualquer pilha de cliente AMQP 1.0 existente em qualquer plataforma possa interagir com o Barramento de Serviço do Azure por meio do AMQP 1.0.

Pilhas AMQP 1.0 comuns de uso geral, como Apache Qpid Proton ou AMQP.NET Lite, implementam todos os elementos principais do protocolo AMQP 1.0, como sessões ou links. Esses elementos fundamentais às vezes são encapsulados com uma API de nível superior; O Apache Proton ainda oferece dois, a API imperativa do Messenger e a API reativa do Reator.

Na discussão a seguir, assumimos que o gerenciamento de conexões, sessões e links AMQP e a manipulação de transferências de quadros e controle de fluxo são manipulados pela respetiva pilha (como o Apache Proton-C) e não exigem muita ou nenhuma atenção específica dos desenvolvedores de aplicativos. Abstratamente, assumimos a existência de algumas primitivas de API, como a capacidade de se conectar e criar alguma forma de objetos de abstração de emissor e recetor, que então têm alguma forma e send() receive() operações, respectivamente.

Ao discutir recursos avançados do Barramento de Serviço do Azure, como navegação de mensagens ou gerenciamento de sessões, esses recursos são explicados em termos AMQP, mas também como uma pseudoimplementação em camadas sobre essa suposta abstração de API.

O que é AMQP?

AMQP é um protocolo de enquadramento e transferência. Enquadramento significa que ele fornece estrutura para fluxos de dados binários que fluem em qualquer direção de uma conexão de rede. A estrutura fornece delineamento para blocos distintos de dados, chamados quadros, a serem trocados entre as partes conectadas. As capacidades de transferência garantem que ambas as partes comunicantes possam estabelecer um entendimento comum sobre quando os quadros devem ser transferidos e quando as transferências devem ser consideradas completas.

Ao contrário das versões de rascunho expiradas anteriores do grupo de trabalho AMQP que ainda estão em uso por alguns agentes de mensagens, o protocolo AMQP 1.0 final e padronizado do grupo de trabalho não prescreve a presença de um agente de mensagens ou qualquer topologia específica para entidades dentro de um agente de mensagens.

O protocolo pode ser usado para comunicação simétrica ponto a ponto, para interação com agentes de mensagens que dão suporte a filas e entidades de publicação/assinatura, como faz o Barramento de Serviço do Azure. Ele também pode ser usado para interação com a infraestrutura de mensagens em que os padrões de interação são diferentes das filas regulares, como é o caso dos Hubs de Eventos do Azure. Um hub de eventos age como uma fila quando os eventos são enviados para ele, mas age mais como um serviço de armazenamento serial quando os eventos são lidos a partir dele; assemelha-se um pouco a uma unidade de fita. O cliente escolhe um deslocamento no fluxo de dados disponível e, em seguida, recebe todos os eventos desse deslocamento para o mais recente disponível.

O protocolo AMQP 1.0 foi projetado para ser extensível, permitindo especificações adicionais para melhorar suas capacidades. As três especificações de extensão discutidas neste documento ilustram-no. Para comunicação através da infraestrutura HTTPS/WebSockets existente, configurar as portas TCP AMQP nativas pode ser difícil. Uma especificação de vinculação define como sobrepor o AMQP em camadas sobre WebSockets. Para interagir com a infraestrutura de mensagens de forma de solicitação/resposta para fins de gerenciamento ou para fornecer funcionalidade avançada, a especificação de gerenciamento AMQP define as primitivas básicas de interação necessárias. Para a integração do modelo de autorização federada, a especificação de segurança baseada em declarações AMQP define como associar e renovar tokens de autorização associados a links.

Cenários básicos de AMQP

Esta seção explica o uso básico do AMQP 1.0 com o Barramento de Serviço do Azure, que inclui a criação de conexões, sessões e links e a transferência de mensagens de e para entidades do Barramento de Serviço, como filas, tópicos e assinaturas.

A fonte mais autorizada para aprender sobre como o AMQP funciona é a especificação AMQP 1.0, mas a especificação foi escrita para orientar precisamente a implementação e não para ensinar o protocolo. Esta seção se concentra na introdução da terminologia necessária para descrever como o Service Bus usa o AMQP 1.0. Para uma introdução mais abrangente ao AMQP e uma discussão mais ampla sobre o AMQP 1.0, revise este curso em vídeo.

Conexões e sessões

O AMQP chama os programas comunicantes de contêineres, que contêm nós, que são as entidades comunicantes dentro desses contêineres. Uma fila pode ser esse nó. AMQP permite a multiplexação, de modo que uma única conexão pode ser usada para muitos caminhos de comunicação entre nós; Por exemplo, um cliente de aplicativo pode receber simultaneamente de uma fila e enviar para outra fila pela mesma conexão de rede.

Diagrama mostrando sessões e conexões entre contêineres.

A conexão de rede é, portanto, ancorada no contêiner. Ele é iniciado pelo contêiner na função cliente fazendo uma conexão de soquete TCP de saída com um contêiner na função de recetor, que escuta e aceita conexões TCP de entrada. O handshake de conexão inclui negociar a versão do protocolo, declarar ou negociar o uso de Transport Level Security (TLS)/Secure Sockets Layer (SSL) e um handshake de autenticação/autorização no escopo da conexão baseado em SASL.

O Barramento de Serviço do Azure ou os Hubs de Eventos do Azure exigem o uso de TLS em todos os momentos. Ele suporta conexões pela porta TCP 5671, em que a conexão TCP é primeiro sobreposta com TLS antes de entrar no handshake do protocolo AMQP, e também suporta conexões pela porta TCP 5672, em que o servidor oferece imediatamente uma atualização obrigatória de conexão para TLS usando o modelo prescrito pelo AMQP. A ligação AMQP WebSockets cria um túnel sobre a porta TCP 443 que é equivalente a conexões AMQP 5671.

Depois de configurar a conexão e o TLS, o Service Bus oferece duas opções de mecanismo SASL:

  • SASL PLAIN é comumente usado para passar credenciais de nome de usuário e senha para um servidor. O Service Bus não tem contas, mas chamadas de regras de Segurança de Acesso Compartilhado, que conferem direitos e estão associadas a uma chave. O nome de uma regra é usado como o nome de usuário e a chave (como texto codificado base64) é usada como a senha. Os direitos associados à regra escolhida regem as operações permitidas na conexão.
  • SASL ANONYMOUS é usado para ignorar a autorização SASL quando o cliente deseja usar o modelo CBS (claims-based-security) descrito posteriormente. Com essa opção, uma conexão de cliente pode ser estabelecida anonimamente por um curto período de tempo, durante o qual o cliente só pode interagir com o ponto de extremidade CBS e o handshake CBS deve ser concluído.

Depois que a conexão de transporte é estabelecida, cada contêiner declara o tamanho máximo do quadro que está disposto a manipular e, após um tempo limite ocioso, eles se desconectam unilateralmente se não houver atividade na conexão.

Eles também declaram quantos canais simultâneos são suportados. Um canal é um caminho de transferência unidirecional, de saída e virtual sobre a conexão. Uma sessão usa um canal de cada um dos contêineres interconectados para formar um caminho de comunicação bidirecional.

As sessões têm um modelo de controle de fluxo baseado em janelas; Quando uma sessão é criada, cada parte declara quantos quadros está disposta a aceitar em sua janela de recebimento. À medida que as partes trocam quadros, os quadros transferidos preenchem essa janela e as transferências param quando a janela está cheia e até que a janela seja redefinida ou expandida usando o fluxo performativo (performativo é o termo AMQP para gestos de nível de protocolo trocados entre as duas partes).

Este modelo baseado em janela é aproximadamente análogo ao conceito TCP de controle de fluxo baseado em janela, mas no nível de sessão dentro do soquete. O conceito do protocolo de permitir várias sessões simultâneas existe para que o tráfego de alta prioridade possa ser ultrapassado pelo tráfego normal limitado, como em uma pista expressa de rodovia.

Atualmente, o Barramento de Serviço do Azure usa exatamente uma sessão para cada conexão. O tamanho máximo do quadro do Service Bus é de 262.144 bytes (256 K bytes) para o Service Bus Standard. É 1048576 (100 MB) para Service Bus Premium e Hubs de Eventos. O Service Bus não impõe nenhuma janela de limitação específica no nível da sessão, mas redefine a janela regularmente como parte do controle de fluxo no nível do link (consulte a próxima seção).

Conexões, canais e sessões são efêmeros. Se a conexão subjacente entrar em colapso, as conexões, o túnel TLS, o contexto de autorização SASL e as sessões deverão ser restabelecidos.

Requisitos de porta de saída AMQP

Os clientes que usam conexões AMQP sobre TCP exigem que as portas 5671 e 5672 sejam abertas no firewall local. Junto com essas portas, pode ser necessário abrir portas adicionais se o recurso EnableLinkRedirect estiver habilitado. EnableLinkRedirect é um novo recurso de mensagens que ajuda a pular um salto ao receber mensagens, ajudando assim a aumentar a taxa de transferência. O cliente começaria a se comunicar diretamente com o serviço de back-end no intervalo de portas 104XX, conforme mostrado na imagem a seguir.

Lista de portos de destino

Um cliente .NET falharia com um SocketException ("Foi feita uma tentativa de acessar um soquete de uma forma proibida por suas permissões de acesso") se essas portas forem bloqueadas pelo firewall. O recurso pode ser desativado definindo EnableAmqpLinkRedirect=false na cadeia de conexão, o que força os clientes a se comunicarem com o serviço remoto pela porta 5671.

A ligação AMQP WebSocket fornece um mecanismo para encapsular uma conexão AMQP em um transporte WebSocket. Essa ligação cria um túnel sobre a porta TCP 443, que é equivalente a conexões AMQP 5671. Use AMQP WebSockets se você estiver atrás de um firewall que bloqueia conexões TCP pelas portas 5671, 5672, mas permite conexões TCP pela porta 443 (https).

AMQP transfere mensagens através de links. Um link é um caminho de comunicação criado ao longo de uma sessão que permite transferir mensagens em uma direção; A negociação do status da transferência é sobre o link e bidirecional entre as partes conectadas.

Captura de tela mostrando uma Sessão carregando uma conexão de link entre dois contêineres.

Os links podem ser criados por qualquer contêiner a qualquer momento e em uma sessão existente, o que torna o AMQP diferente de muitos outros protocolos, incluindo HTTP e MQTT, onde o início de transferências e o caminho de transferência é um privilégio exclusivo da parte que cria a conexão de soquete.

O contêiner de início de link solicita que o contêiner oposto aceite um link e escolhe uma função de remetente ou recetor. Portanto, qualquer contêiner pode iniciar a criação de caminhos de comunicação unidirecionais ou bidirecionais, com os últimos modelados como pares de links.

Os links são nomeados e associados a nós. Como dito no início, nós são as entidades comunicantes dentro de um contêiner.

No Service Bus, um nó é diretamente equivalente a uma fila, um tópico, uma assinatura ou uma subfila de letra morta de uma fila ou assinatura. O nome do nó usado no AMQP é, portanto, o nome relativo da entidade dentro do namespace do Service Bus. Se uma fila for nomeada myqueue, esse também será o nome do nó AMQP. Uma assinatura de tópico segue a convenção da API HTTP sendo classificada em uma coleção de recursos de "assinaturas" e, portanto, um sub de assinatura em um tópico mytopic tem o nome do nó AMQP mytopic/subscriptions/sub.

O cliente de conexão também é obrigado a usar um nome de nó local para criar links; O Service Bus não é prescritivo sobre esses nomes de nó e não os interpreta. As pilhas de clientes AMQP 1.0 geralmente usam um esquema para garantir que esses nomes de nó efêmeros sejam exclusivos no escopo do cliente.

Transferências

Uma vez estabelecido um link, as mensagens podem ser transferidas através desse link. No AMQP, uma transferência é executada com um gesto de protocolo explícito (a transferência performativa) que move uma mensagem do remetente para o recetor através de um link. Uma transferência fica completa quando é «liquidada», o que significa que ambas as partes estabeleceram um entendimento comum do resultado dessa transferência.

Um diagrama que mostra a transferência de uma mensagem entre o Remetente e o Recetor e a disposição que resulta dela.

No caso mais simples, o remetente pode optar por enviar mensagens "pré-resolvidas", o que significa que o cliente não está interessado no resultado e o destinatário não fornece nenhum feedback sobre o resultado da operação. Esse modo é suportado pelo Service Bus no nível do protocolo AMQP, mas não é exposto em nenhuma das APIs do cliente.

O caso comum é que as mensagens estão sendo enviadas sem problemas, e o recetor então indica aceitação ou rejeição usando a disposição performativa. A rejeição ocorre quando o recetor não pode aceitar a mensagem por qualquer motivo, e a mensagem de rejeição contém informações sobre o motivo, que é uma estrutura de erro definida pelo AMQP. Se as mensagens forem rejeitadas devido a erros internos dentro do Service Bus, o serviço retornará informações extras dentro dessa estrutura que podem ser usadas para fornecer dicas de diagnóstico ao pessoal de suporte se você estiver preenchendo solicitações de suporte. Você aprenderá mais detalhes sobre os erros mais tarde.

Uma forma especial de rejeição é o estado liberado , que indica que o destinatário não tem qualquer objeção técnica à transferência, mas também não tem interesse em liquidar a transferência. Esse caso existe, por exemplo, quando uma mensagem é entregue a um cliente do Service Bus e o cliente opta por "abandonar" a mensagem porque não pode executar o trabalho resultante do processamento da mensagem; a entrega da mensagem em si não é culpada. Uma variação desse estado é o estado modificado , que permite alterações na mensagem à medida que ela é liberada. Esse estado não é usado pelo Service Bus no momento.

A especificação AMQP 1.0 define um estado de disposição adicional chamado recebido, que ajuda especificamente a lidar com a recuperação de link. A recuperação de link permite reconstituir o estado de um link e quaisquer entregas pendentes em cima de uma nova conexão e sessão, quando a conexão e a sessão anteriores foram perdidas.

O Service Bus não oferece suporte à recuperação de links; se o cliente perder a conexão com o Service Bus com uma transferência de mensagem não resolvida pendente, essa transferência de mensagem será perdida e o cliente deverá se reconectar, restabelecer o link e tentar novamente a transferência.

Como tal, o Service Bus e os Hubs de Eventos suportam a transferência "pelo menos uma vez", onde o remetente pode ter certeza de que a mensagem foi armazenada e aceita, mas não suportam transferências "exatamente uma vez" no nível AMQP, onde o sistema tentaria recuperar o link e continuar a negociar o estado de entrega para evitar a duplicação da transferência de mensagens.

Para compensar possíveis envios duplicados, o Service Bus oferece suporte à deteção de duplicados como um recurso opcional em filas e tópicos. A deteção de duplicados registra os IDs de todas as mensagens recebidas durante uma janela de tempo definida pelo usuário e, em seguida, descarta silenciosamente todas as mensagens enviadas com os mesmos IDs de mensagem durante essa mesma janela.

Controlo de fluxo

Além do modelo de controle de fluxo no nível de sessão discutido anteriormente, cada link tem seu próprio modelo de controle de fluxo. O controle de fluxo no nível da sessão protege o contêiner de ter que lidar com muitos quadros ao mesmo tempo, o controle de fluxo no nível do link coloca o aplicativo no comando de quantas mensagens ele deseja manipular a partir de um link e quando.

Captura de ecrã de um registo a mostrar Origem, Destino, Porta de Origem, Porta de Destino e Nome do Protocolo. Na primeira linha, a Porta de Destino 10401 (0x28 A 1) é delineada em preto.

Em um link, as transferências só podem acontecer quando o remetente tiver crédito de link suficiente. Link credit é um contador definido pelo recetor usando o fluxo performativo, que é definido para um link. Quando o remetente recebe crédito de link, ele tenta usar esse crédito entregando mensagens. Cada entrega de mensagem diminui o crédito de link restante em 1. Quando o crédito do link é usado, as entregas param.

Quando o Service Bus está na função de recetor, ele fornece instantaneamente ao remetente um amplo crédito de link, para que as mensagens possam ser enviadas imediatamente. À medida que o crédito de link é usado, o Service Bus ocasionalmente envia um fluxo performativo para o remetente para atualizar o saldo de crédito do link.

Na função de remetente, o Service Bus envia mensagens para usar qualquer crédito de link pendente.

Uma chamada "receber" no nível da API se traduz em um fluxo performativo sendo enviado ao Service Bus pelo cliente, e o Service Bus consome esse crédito pegando a primeira mensagem disponível e desbloqueada da fila, bloqueando-a e transferindo-a. Se não houver nenhuma mensagem prontamente disponível para entrega, qualquer crédito pendente por qualquer link estabelecido com essa entidade específica permanece registrado em ordem de chegada, e as mensagens são bloqueadas e transferidas à medida que ficam disponíveis, para usar qualquer crédito pendente.

O bloqueio de uma mensagem é liberado quando a transferência é liquidada em um dos estados do terminal aceitos, rejeitados ou liberados. A mensagem é removida do Service Bus quando o estado do terminal é aceito. Ele permanece no Service Bus e é entregue ao próximo recetor quando a transferência chega a qualquer um dos outros estados. O Service Bus move automaticamente a mensagem para a fila de mensagens mortas da entidade quando atinge a contagem máxima de entrega permitida para a entidade devido a repetidas rejeições ou liberações.

Embora as APIs do Service Bus não exponham diretamente essa opção atualmente, um cliente de protocolo AMQP de nível inferior pode usar o modelo link-credit para transformar a interação "pull-style" de emitir uma unidade de crédito para cada solicitação de recebimento em um modelo "push-style", emitindo um grande número de créditos de link e, em seguida, receber mensagens à medida que ficam disponíveis sem qualquer interação adicional. O push é suportado por meio das configurações da propriedade ServiceBusProcessor.PrefetchCount ou ServiceBusReceiver.PrefetchCount . Quando eles são diferentes de zero, o cliente AMQP usa-o como o crédito de link.

Neste contexto, é importante entender que o relógio para a expiração do bloqueio na mensagem dentro da entidade começa quando a mensagem é retirada da entidade, não quando a mensagem é colocada no fio. Sempre que o cliente indicar disponibilidade para receber mensagens através da emissão de crédito de link, espera-se, portanto, que esteja ativamente puxando mensagens pela rede e esteja pronto para lidar com elas. Caso contrário, o bloqueio de mensagem pode ter expirado antes mesmo de a mensagem ser entregue. A utilização do controlo do fluxo de ligação e crédito deve refletir diretamente a disponibilidade imediata para lidar com as mensagens disponíveis enviadas para o destinatário.

Em resumo, as seções a seguir fornecem uma visão geral esquemática do fluxo performativo durante diferentes interações de API. Cada seção descreve uma operação lógica diferente. Algumas dessas interações podem ser "preguiçosas", o que significa que só podem ser realizadas quando necessário. Criar um remetente de mensagem pode não causar uma interação de rede até que a primeira mensagem seja enviada ou solicitada.

As setas na tabela a seguir mostram a direção do fluxo performativo.

Criar recetor de mensagens

Cliente Service Bus
--> attach(<br/>name={link name},<br/>handle={numeric handle},<br/>role=**receiver**,<br/>source={entity name},<br/>target={client link ID}<br/>) Cliente anexa à entidade como destinatário
Respostas do Barramento de Serviço anexando o final do link <-- attach(<br/>name={link name},<br/>handle={numeric handle},<br/>role=**sender**,<br/>source={entity name},<br/>target={client link ID}<br/>)

Criar remetente de mensagem

Cliente Service Bus
--> attach(<br/>name={link name},<br/>handle={numeric handle},<br/>role=**sender**,<br/>source={client link ID},<br/>target={entity name}<br/>) Sem ação
Sem ação <-- attach(<br/>name={link name},<br/>handle={numeric handle},<br/>role=**receiver**,<br/>source={client link ID},<br/>target={entity name}<br/>)

Criar remetente de mensagem (erro)

Cliente Service Bus
--> attach(<br/>name={link name},<br/>handle={numeric handle},<br/>role=**sender**,<br/>source={client link ID},<br/>target={entity name}<br/>) Sem ação
Sem ação <-- attach(<br/>name={link name},<br/>handle={numeric handle},<br/>role=**receiver**,<br/>source=null,<br/>target=null<br/>)<br/><br/><-- detach(<br/>handle={numeric handle},<br/>closed=**true**,<br/>error={error info}<br/>)

Fechar o recetor/remetente da mensagem

Cliente Service Bus
--> detach(<br/>handle={numeric handle},<br/>closed=**true**<br/>) Sem ação
Sem ação <-- detach(<br/>handle={numeric handle},<br/>closed=**true**<br/>)

Enviar (sucesso)

Cliente Service Bus
--> transfer(<br/>delivery-id={numeric handle},<br/>delivery-tag={binary handle},<br/>settled=**false**,,more=**false**,<br/>state=**null**,<br/>resume=**false**<br/>) Sem ação
Sem ação <-- disposition(<br/>role=receiver,<br/>first={delivery ID},<br/>last={delivery ID},<br/>settled=**true**,<br/>state=**accepted**<br/>)

Enviar (erro)

Cliente Service Bus
--> transfer(<br/>delivery-id={numeric handle},<br/>delivery-tag={binary handle},<br/>settled=**false**,,more=**false**,<br/>state=**null**,<br/>resume=**false**<br/>) Sem ação
Sem ação <-- disposition(<br/>role=receiver,<br/>first={delivery ID},<br/>last={delivery ID},<br/>settled=**true**,<br/>state=**rejected**(<br/>error={error info}<br/>)<br/>)

Receber

Cliente Service Bus
--> flow(<br/>link-credit=1<br/>) Sem ação
Sem ação < transfer(<br/>delivery-id={numeric handle},<br/>delivery-tag={binary handle},<br/>settled=**false**,<br/>more=**false**,<br/>state=**null**,<br/>resume=**false**<br/>)
--> disposition(<br/>role=**receiver**,<br/>first={delivery ID},<br/>last={delivery ID},<br/>settled=**true**,<br/>state=**accepted**<br/>) Sem ação

Recebimento de várias mensagens

Cliente Service Bus
--> flow(<br/>link-credit=3<br/>) Sem ação
Sem ação < transfer(<br/>delivery-id={numeric handle},<br/>delivery-tag={binary handle},<br/>settled=**false**,<br/>more=**false**,<br/>state=**null**,<br/>resume=**false**<br/>)
Sem ação < transfer(<br/>delivery-id={numeric handle+1},<br/>delivery-tag={binary handle},<br/>settled=**false**,<br/>more=**false**,<br/>state=**null**,<br/>resume=**false**<br/>)
Sem ação < transfer(<br/>delivery-id={numeric handle+2},<br/>delivery-tag={binary handle},<br/>settled=**false**,<br/>more=**false**,<br/>state=**null**,<br/>resume=**false**<br/>)
--> disposition(<br/>role=receiver,<br/>first={delivery ID},<br/>last={delivery ID+2},<br/>settled=**true**,<br/>state=**accepted**<br/>) Sem ação

Mensagens

As seções a seguir explicam quais propriedades das seções de mensagem AMQP padrão são usadas pelo Service Bus e como elas são mapeadas para o conjunto de APIs do Service Bus.

Qualquer propriedade que o aplicativo precise definir deve ser mapeada para o mapa do application-properties AMQP.

Nome do Campo Utilização Nome da API
durável - -
prioridade - -
ttl Tempo de vida para esta mensagem TimeToLive
primeiro-adquirente - -
contagem de entregas - DeliveryCount

Propriedades

Nome do Campo Utilização Nome da API
message-id Identificador de forma livre definido pelo aplicativo para esta mensagem. Usado para deteção de duplicatas. MessageId
user-id Identificador de usuário definido pelo aplicativo, não interpretado pelo Service Bus. Não acessível através da API do Service Bus.
to Identificador de destino definido pelo aplicativo, não interpretado pelo Service Bus. De
subject Identificador de finalidade de mensagem definido pelo aplicativo, não interpretado pelo Service Bus. Assunto
reply-to Indicador de caminho de resposta definido pelo aplicativo, não interpretado pelo Service Bus. ReplyTo
correlation-id Identificador de correlação definido pelo aplicativo, não interpretado pelo Service Bus. CorrelationId
content-type Indicador de tipo de conteúdo definido pelo aplicativo para o corpo, não interpretado pelo Service Bus. Tipo de conteúdo
content-encoding Indicador de codificação de conteúdo definido pelo aplicativo para o corpo, não interpretado pelo Service Bus. Não acessível através da API do Service Bus.
absolute-expiry-time Declara em que instante absoluto a mensagem expira. Ignorado na entrada (o cabeçalho TTL é observado), autoritativo na saída. Não acessível através da API do Service Bus.
creation-time Declara em que momento a mensagem foi criada. Não utilizado pelo Service Bus Não acessível através da API do Service Bus.
group-id Identificador definido pelo aplicativo para um conjunto relacionado de mensagens. Usado para sessões do Service Bus. SessionId
group-sequence Contador que identifica o número de sequência relativo da mensagem dentro de uma sessão. Ignorado pelo Service Bus. Não acessível através da API do Service Bus.
reply-to-group-id - ReplyToSessionId

Anotações de mensagem

Existem algumas outras propriedades de mensagem do barramento de serviço, que não fazem parte das propriedades da mensagem AMQP e são passadas como MessageAnnotations na mensagem.

Chave do mapa de anotação Utilização Nome da API
x-opt-scheduled-enqueue-time Declara em que momento a mensagem deve aparecer na entidade ScheduledEnqueueTime
x-opt-partition-key Chave definida pelo aplicativo que dita em qual partição a mensagem deve chegar. PartitionKey
x-opt-via-partition-key Valor de chave de partição definido pelo aplicativo quando uma transação deve ser usada para enviar mensagens por meio de uma fila de transferência. TransactionPartitionKey
x-opt-enqueued-time Hora UTC definida pelo serviço que representa a hora real de enfileiramento da mensagem. Ignorado na entrada. EnqueuedTime
x-opt-sequence-number Número exclusivo definido pelo serviço atribuído a uma mensagem. Número de Sequência
x-opt-offset Número de sequência enfileirado definido pelo serviço da mensagem. EnqueuedSequenceNumber
x-opt-locked-until Serviço definido. A data e hora até a qual a mensagem será bloqueada na fila/assinatura. BloqueadoAté
x-opt-deadletter-source Serviço definido. Se a mensagem for recebida da fila de letras mortas, ela representa a origem da mensagem original. DeadLetterSource

Capacidade de transação

Uma transação agrupa duas ou mais operações num âmbito de execução. Por natureza, essa operação deve assegurar que todas as operações pertencentes a um determinado grupo de operações sejam bem sucedidas ou fracassem conjuntamente. As operações são agrupadas por um identificador txn-id.

Para interação transacional, o cliente atua como um transaction controller , que controla as operações que devem ser agrupadas. O Serviço Service Bus atua como um transactional resource e executa o trabalho conforme solicitado pelo transaction controller.

O cliente e o serviço comunicam através de um control link , que é estabelecido pelo cliente. As declare mensagens e discharge são enviadas pelo controlador através do link de controle para alocar e concluir transações, respectivamente (elas não representam a demarcação do trabalho transacional). O envio/recebimento real não é realizado neste link. Cada operação transacional solicitada é explicitamente identificada com a desejada txn-id e, portanto, pode ocorrer em qualquer link na Conexão. Se o link de controle for fechado enquanto existirem transações não descarregadas que ele criou, todas essas transações serão imediatamente revertidas, e as tentativas de executar mais trabalho transacional nelas levarão à falha. As mensagens no link de controle não devem ser pré-liquidadas.

Cada conexão tem que iniciar seu próprio link de controle para poder iniciar e terminar transações. O serviço define um destino especial que funciona como um coordinatorarquivo . O cliente/controlador estabelece um link de controle para esse destino. O link de controle está fora do limite de uma entidade, ou seja, o mesmo link de controle pode ser usado para iniciar e descarregar transações para várias entidades.

Iniciar uma transação

Para iniciar o trabalho transacional, o controlador deve obter um txn-id do coordenador. Ele faz isso enviando uma declare mensagem de tipo. Se a declaração for bem-sucedida, o coordenador responde com um resultado de disposição, que carrega o .txn-id

Cliente (Controlador) Direção Service Bus (Coordenador)
attach(<br/>name={link name},<br/>... ,<br/>role=**sender**,<br/>target=**Coordinator**<br/>) ------>
<------ attach(<br/>name={link name},<br/>... ,<br/>target=Coordinator()<br/>)
transfer(<br/>delivery-id=0, ...)<br/>{ AmqpValue (**Declare()**)} ------>
<------ disposition( <br/> first=0, last=0, <br/>state=**Declared**(<br/>**txn-id**={transaction ID}<br/>))

Quitação de uma transação

O controlador conclui o trabalho transacional enviando uma discharge mensagem ao coordenador. O controlador indica que deseja comprometer ou reverter o trabalho transacional colocando a fail bandeira no corpo de descarga. Se o coordenador não conseguir concluir a quitação, a mensagem é rejeitada com este resultado contendo o transaction-error.

Nota: fail=true refere-se a Rollback de uma transação, e fail=false refere-se a Commit.

Cliente (Controlador) Direção Service Bus (Coordenador)
transfer(<br/>delivery-id=0, ...)<br/>{ AmqpValue (Declare())} ------>
<------ disposition( <br/> first=0, last=0, <br/>state=Declared(<br/>txn-id={transaction ID}<br/>))
. . .
Trabalho transacional
em outros links
. . .
transfer(<br/>delivery-id=57, ...)<br/>{ AmqpValue (<br/>**Discharge(txn-id=0,<br/>fail=false)**)} ------>
<------ disposition( <br/> first=57, last=57, <br/>state=**Accepted()**)

Enviar uma mensagem numa transação

Todo o trabalho transacional é feito com o estado transactional-state de entrega transacional que carrega o txn-id. Ao enviar mensagens, o estado transacional é transportado pelo quadro de transferência da mensagem.

Cliente (Controlador) Direção Service Bus (Coordenador)
transfer(<br/>delivery-id=0, ...)<br/>{ AmqpValue (Declare())} ------>
<------ disposition( <br/> first=0, last=0, <br/>state=Declared(<br/>txn-id={transaction ID}<br/>))
transfer(<br/>handle=1,<br/>delivery-id=1, <br/>**state=<br/>TransactionalState(<br/>txn-id=0)**)<br/>{ payload } ------>
<------ disposition( <br/> first=1, last=1, <br/>state=**TransactionalState(<br/>txn-id=0,<br/>outcome=Accepted()**))

Eliminar uma mensagem numa transação

A disposição de mensagens inclui operações como CompleteDeadLetter / DeferAbandon / / . Para realizar essas operações dentro de uma transação, passe o transactional-state com a disposição.

Cliente (Controlador) Direção Service Bus (Coordenador)
transfer(<br/>delivery-id=0, ...)<br/>{ AmqpValue (Declare())} ------>
<------ disposition( <br/> first=0, last=0, <br/>state=Declared(<br/>txn-id={transaction ID}<br/>))
<------ transfer(<br/>handle=2,<br/>delivery-id=11, <br/>state=null)<br/>{ payload }
disposition( <br/> first=11, last=11, <br/>state=**TransactionalState(<br/>txn-id=0,<br/>outcome=Accepted()**)) ------>

Recursos avançados do Service Bus

Esta seção aborda os recursos avançados do Barramento de Serviço do Azure que se baseiam em extensões de rascunho para AMQP, atualmente em desenvolvimento no Comitê Técnico do OASIS para AMQP. O Service Bus implementa as versões mais recentes desses rascunhos e adota as alterações introduzidas à medida que esses rascunhos atingem o status padrão.

Nota

As operações avançadas do Service Bus Messaging são suportadas por meio de um padrão de solicitação/resposta. Os detalhes dessas operações são descritos no artigo AMQP 1.0 em Service Bus: request-response-based operations.

Gestão AMQP

A especificação de gerenciamento AMQP é a primeira das extensões de rascunho discutidas neste artigo. Esta especificação define um conjunto de protocolos em camadas sobre o protocolo AMQP que permite interações de gerenciamento com a infraestrutura de mensagens através do AMQP. A especificação define operações genéricas, como criar, ler, atualizar e excluir para gerenciar entidades dentro de uma infraestrutura de mensagens e um conjunto de operações de consulta.

Todos esses gestos exigem uma interação de solicitação/resposta entre o cliente e a infraestrutura de mensagens e, portanto, a especificação define como modelar esse padrão de interação sobre o AMQP: o cliente se conecta à infraestrutura de mensagens, inicia uma sessão e, em seguida, cria um par de links. Em um link, o cliente atua como emissor e no outro ele atua como recetor, criando assim um par de links que podem atuar como um canal bidirecional.

Operação lógica Cliente Service Bus
Criar caminho de resposta de solicitação --> attach(<br/>name={*link name*},<br/>handle={*numeric handle*},<br/>role=**sender**,<br/>source=**null**,<br/>target=”myentity/$management”<br/>) Sem ação
Criar caminho de resposta de solicitação Sem ação \<-- attach(<br/>name={*link name*},<br/>handle={*numeric handle*},<br/>role=**receiver**,<br/>source=null,<br/>target=”myentity”<br/>)
Criar caminho de resposta de solicitação --> attach(<br/>name={*link name*},<br/>handle={*numeric handle*},<br/>role=**receiver**,<br/>source=”myentity/$management”,<br/>target=”myclient$id”<br/>)
Criar caminho de resposta de solicitação Sem ação \<-- attach(<br/>name={*link name*},<br/>handle={*numeric handle*},<br/>role=**sender**,<br/>source=”myentity”,<br/>target=”myclient$id”<br/>)

Tendo esse par de links no lugar, a implementação de solicitação/resposta é simples: uma solicitação é uma mensagem enviada para uma entidade dentro da infraestrutura de mensagens que entende esse padrão. Nessa mensagem de solicitação, o campo de resposta na seção de propriedades é definido como o identificador de destino do link no qual a resposta será entregue. A entidade de tratamento processa a solicitação e, em seguida, entrega a resposta pelo link cujo identificador de destino corresponde ao identificador de resposta indicado.

O padrão obviamente requer que o contêiner do cliente e o identificador gerado pelo cliente para o destino da resposta sejam exclusivos em todos os clientes e, por motivos de segurança, também difíceis de prever.

As trocas de mensagens usadas para o protocolo de gerenciamento e para todos os outros protocolos que usam o mesmo padrão acontecem no nível do aplicativo; eles não definem novos gestos no nível do protocolo AMQP. Isso é intencional, para que os aplicativos possam tirar proveito imediato dessas extensões com pilhas AMQP 1.0 compatíveis.

Atualmente, o Service Bus não implementa nenhum dos principais recursos da especificação de gerenciamento, mas o padrão de solicitação/resposta definido pela especificação de gerenciamento é fundamental para o recurso de segurança baseada em declarações e para quase todos os recursos avançados discutidos nas seções a seguir:

Autorização baseada em declarações

O rascunho de especificação do AMQP Claims-Based-Authorization (CBS) baseia-se no padrão de solicitação/resposta da especificação de gerenciamento e descreve um modelo generalizado de como usar tokens de segurança federados com o AMQP.

O modelo de segurança padrão do AMQP discutido na introdução é baseado em SASL e integra-se com o handshake de conexão AMQP. O uso do SASL tem a vantagem de fornecer um modelo extensível para o qual foi definido um conjunto de mecanismos dos quais qualquer protocolo que formalmente se apoie no SASL pode se beneficiar. Entre esses mecanismos estão "PLAIN" para transferência de nomes de usuário e senhas, "EXTERNAL" para vincular à segurança de nível TLS, "ANONYMOUS" para expressar a ausência de autenticação/autorização explícita e uma ampla variedade de mecanismos adicionais que permitem passar credenciais ou tokens de autenticação e/ou autorização.

A integração SASL da AMQP tem duas desvantagens:

  • Todas as credenciais e tokens têm como escopo a conexão. Uma infraestrutura de mensagens pode querer fornecer controle de acesso diferenciado por entidade; por exemplo, permitindo que o portador de um token envie para a fila A, mas não para a fila B. Com o contexto de autorização ancorado na conexão, não é possível usar uma única conexão e ainda usar tokens de acesso diferentes para a fila A e a fila B.
  • Normalmente, os tokens de acesso são válidos apenas por um período limitado. Essa validade exige que o usuário readquira tokens periodicamente e oferece uma oportunidade ao emissor do token de recusar a emissão de um novo token se as permissões de acesso do usuário tiverem sido alteradas. As conexões AMQP podem durar por longos períodos de tempo. O modelo SASL só oferece a chance de definir um token no momento da conexão, o que significa que a infraestrutura de mensagens tem que desconectar o cliente quando o token expira ou precisa aceitar o risco de permitir a comunicação contínua com um cliente cujos direitos de acesso podem ter sido revogados nesse ínterim.

A especificação AMQP CBS, implementada pelo Service Bus, permite uma solução elegante para ambos os problemas: permite que um cliente associe tokens de acesso a cada nó e atualize esses tokens antes que eles expirem, sem interromper o fluxo de mensagens.

O CBS define um nó de gerenciamento virtual, chamado $cbs, a ser fornecido pela infraestrutura de mensagens. O nó de gerenciamento aceita tokens em nome de quaisquer outros nós na infraestrutura de mensagens.

O gesto de protocolo é uma troca de solicitação/resposta, conforme definido pela especificação de gerenciamento. Isso significa que o cliente estabelece um par de links com o nó $cbs e, em seguida, passa uma solicitação no link de saída e, em seguida, aguarda a resposta no link de entrada.

A mensagem de solicitação tem as seguintes propriedades do aplicativo:

Chave Opcional Tipo de Valor Conteúdo do valor
operation Não string put-token
type Não string O tipo do token que está sendo colocado.
name Não string O "público" ao qual o token se aplica.
expiration Sim carimbo de data/hora O tempo de expiração do token.

A propriedade name identifica a entidade à qual o token deve ser associado. No Service Bus, é o caminho para a fila ou tópico/assinatura. A propriedade type identifica o tipo de token:

Tipo de token Descrição do token Tipo de Corpo Notas
jwt Token Web JSON (JWT) Valor AMQP (string)
servicebus.windows.net:sastoken Service Bus SAS Token Valor AMQP (string) -

Os tokens conferem direitos. O Service Bus conhece três direitos fundamentais: "Enviar" permite enviar, "Ouvir" permite receber e "Gerir" permite manipular entidades. Os tokens SAS do Service Bus referem-se a regras configuradas no namespace ou entidade, e essas regras são configuradas com direitos. Assinar o token com a chave associada a essa regra faz com que o token expresse os respetivos direitos. O token associado a uma entidade usando put-token permite que o cliente conectado interaja com a entidade de acordo com os direitos de token. Um link onde o cliente assume o papel de remetente requer o direito de "Enviar", assumir o papel de recetor requer o direito de "Ouvir".

A mensagem de resposta tem os seguintes valores de propriedades do aplicativo:

Chave Opcional Tipo de Valor Conteúdo do valor
status-code Não número inteiro Código de resposta HTTP [RFC2616].
status-description Sim string Descrição do estado.

O cliente pode chamar put-token repetidamente e para qualquer entidade na infraestrutura de mensagens. Os tokens têm como escopo o cliente atual e são ancorados na conexão atual, o que significa que o servidor descarta todos os tokens retidos quando a conexão cai.

A implementação atual do Service Bus só permite CBS em conjunto com o método SASL "ANONYMOUS". Uma conexão SSL/TLS sempre deve existir antes do handshake SASL.

O mecanismo ANONYMOUS deve, portanto, ser suportado pelo cliente AMQP 1.0 escolhido. O acesso anônimo significa que o handshake de conexão inicial, incluindo a criação da sessão inicial, acontece sem que o Service Bus saiba quem está criando a conexão.

Uma vez estabelecida a conexão e a sessão, anexar os links ao nó $cbs e enviar a solicitação put-token são as únicas operações permitidas. Um token válido deve ser definido com êxito usando uma solicitação put-token para algum nó de entidade dentro de 20 segundos após a conexão ter sido estabelecida, caso contrário, a conexão será descartada unilateralmente pelo Service Bus.

O cliente é posteriormente responsável por acompanhar a expiração do token. Quando um token expira, o Service Bus descarta imediatamente todos os links na conexão com a respetiva entidade. Para evitar que o problema ocorra, o cliente pode substituir o token do nó por um novo a qualquer momento através do nó de gerenciamento de $cbs virtual com o mesmo gesto put-token e sem atrapalhar o tráfego de carga útil que flui em links diferentes.

Funcionalidade de envio via

O remetente de envio/transferência é uma funcionalidade que permite encaminhar uma determinada mensagem para uma entidade de destino por meio de outra entidade. Esse recurso é usado para executar operações entre entidades em uma única transação.

Com essa funcionalidade, você cria um remetente e estabelece o link para o via-entity. Ao estabelecer o link, informações adicionais são passadas para estabelecer o verdadeiro destino das mensagens/transferências neste link. Uma vez que o anexo tenha sido bem-sucedido, todas as mensagens enviadas neste link são automaticamente encaminhadas para a entidade de destino através da via-entidade.

Nota: A autenticação deve ser realizada tanto para via-entidade quanto para entidade-destino antes de estabelecer este link.

Cliente Direção Service Bus
attach(<br/>name={link name},<br/>role=sender,<br/>source={client link ID},<br/>target=**{via-entity}**,<br/>**properties=map [(<br/>com.microsoft:transfer-destination-address=<br/>{destination-entity} )]** ) ------>
<------ attach(<br/>name={link name},<br/>role=receiver,<br/>source={client link ID},<br/>target={via-entity},<br/>properties=map [(<br/>com.microsoft:transfer-destination-address=<br/>{destination-entity} )] )

Para saber mais sobre o AMQP, consulte Visão geral do AMQP do Service Bus.