RabbitMQ e relação entre canal e conexão

176

O cliente Java RabbitMQ possui os seguintes conceitos:

  • Connection - uma conexão com uma instância do servidor RabbitMQ
  • Channel - ???
  • Conjunto de encadeamentos do consumidor - um conjunto de encadeamentos que consomem mensagens das filas do servidor RabbitMQ
  • Fila - uma estrutura que mantém as mensagens na ordem FIFO

Estou tentando entender o relacionamento e , mais importante , as associações entre eles.

  1. Ainda não tenho muita certeza do que Channelé, além do fato de que essa é a estrutura da qual você publica e consome, e que é criada a partir de uma conexão aberta. Se alguém puder me explicar o que o "Canal" representa, isso poderá ajudar a esclarecer algumas coisas.
  2. Qual é a relação entre Canal e Fila? O mesmo canal pode ser usado para se comunicar com várias filas ou precisa ser 1: 1?
  3. Qual é o relacionamento entre a fila e o pool de consumidores? Vários consumidores podem ser inscritos na mesma fila? Várias filas podem ser consumidas pelo mesmo consumidor? Ou o relacionamento é 1: 1?

Agradecemos antecipadamente por qualquer ajuda aqui!


fonte
As respostas a essa pergunta me levaram a relatar esse problema com o cliente golang, em vez de fazer a pergunta aqui.
Bruce Adams
O canal é um conceito lógico usado para multiplexar uma única conexão TCP física entre um cliente e um nó. O número do canal está incluído no cabeçalho da mensagem do quadro AMQP.
ymas 5/07

Respostas:

196
  1. A Connectionrepresenta uma conexão TCP real com o intermediário de mensagens, enquanto a Channelé uma conexão virtual (conexão AMQP) dentro dele. Dessa forma, você pode usar quantas conexões (virtuais) quiser dentro do aplicativo sem sobrecarregar o broker com conexões TCP.

  2. Você pode usar um Channelpara tudo. No entanto, se você tiver vários threads, é recomendável usar um diferente Channelpara cada thread.

    Segurança de encadeamento de canal no Java Client API Guide :

    Instâncias de canal são seguras para uso por vários threads. As solicitações em um canal são serializadas, com apenas um encadeamento capaz de executar um comando no canal por vez. Mesmo assim, os aplicativos devem preferir usar um canal por thread em vez de compartilhar o mesmo canal em vários threads.

    Não há relação direta entre Channele Queue. A Channelé usado para enviar comandos AMQP para o broker. Isso pode ser a criação de uma fila ou similar, mas esses conceitos não estão ligados.

  3. Cada um Consumeré executado em seu próprio encadeamento alocado no conjunto de encadeamentos do consumidor. Se vários Consumidores forem inscritos na mesma Fila, o broker usará round-robin para distribuir as mensagens entre eles igualmente. Consulte o Tutorial dois: "Filas de trabalho" .

    Também é possível anexar o mesmo Consumera várias filas. Você pode entender os consumidores como retornos de chamada. Eles são chamados toda vez que uma mensagem chega em uma fila à qual o consumidor está vinculado. Para o caso do Java Client, cada Consumidor possui um método handleDelivery(...), que representa o método de retorno de chamada. O que você normalmente faz é subclasse DefaultConsumere substituição handleDelivery(...). Nota: Se você anexar a mesma instância do Consumidor a várias filas, esse método será chamado por diferentes threads. Portanto, cuide da sincronização, se necessário.

Bengt
fonte
4
Apenas para adicionar a partir da documentação: Os retornos de chamada para consumidores são despachados em um thread separado do thread gerenciado pelo Connection. Isso significa que os consumidores podem chamar com segurança métodos de bloqueio na conexão ou canal, como queueDeclare, txCommit, basicCancel ou basicPublish. Cada canal tem seu próprio encadeamento de despacho. Para o caso de uso mais comum de um consumidor por canal, isso significa que os consumidores não retêm outros consumidores. Se você tiver vários Consumidores por canal, saiba que um Consumidor de longa duração pode reter o envio de retornos de chamada para outros Consumidores nesse Canal.
filip
1
Se você anexar a mesma instância Consumer a várias filas do mesmo canal, isso significaria que os retornos de chamada são despachados no mesmo encadeamento. Nesse caso, você não precisaria de sincronização, precisaria?
Filip
Posso usar apenas uma conexão e usar um conjunto de canais em vez de um conjunto de conexões? Isso afetará o rendimento da publicação de mensagens?
qeek
4
Penso que esta referência à Java Client API está desatualizada e, de fato, a referência de hoje contradiz diretamente a citação nesta resposta. A referência de hoje diz que "Instâncias de canal não devem ser compartilhadas entre threads".
Edwin Dalorzo
1
@ EdwinDalorzo - parece que quem escreveu originalmente a documentação não entendeu completamente a dicotomia de conexão de canal. A arquitetura fundamental do AMQP 0.9.1 realmente trata um canal como uma sessão, portanto, diferentes segmentos que compartilham uma sessão são realmente absurdos. Meu palpite é que essa é a razão da mudança.
theMayer
53

Uma boa compreensão conceitual do que o protocolo AMQP faz "sob o capô" é útil aqui. Eu diria que a documentação e a API que o AMQP 0.9.1 optou por implantar tornam isso particularmente confuso, de modo que a questão em si é aquela que muitas pessoas precisam enfrentar.

TL; DR

Uma conexão é o soquete TCP negociado físico com o servidor AMQP. Os clientes implementados adequadamente terão um desses por aplicativo, thread-safe, compartilhável entre threads.

Um canal é uma única sessão de aplicativo na conexão. Um encadeamento terá uma ou mais dessas sessões. A arquitetura AMQP 0.9.1 é que eles não devem ser compartilhados entre os threads e devem ser fechados / destruídos quando o thread que o criou terminar com ele. Eles também são fechados pelo servidor quando ocorrem várias violações de protocolo.

Um consumidor é uma construção virtual que representa a presença de uma "caixa de correio" em um canal específico. O uso de um consumidor informa ao broker para enviar mensagens de uma fila específica para o nó de extremidade do canal.

Fatos da conexão

Primeiro, como outros apontaram corretamente, uma conexão é o objeto que representa a conexão TCP real com o servidor. As conexões são especificadas no nível do protocolo no AMQP, e toda a comunicação com o broker ocorre através de uma ou mais conexões.

  • Por ser uma conexão TCP real, ela possui um endereço IP e um número de porta.
  • Os parâmetros do protocolo são negociados por cliente como parte da configuração da conexão (um processo conhecido como handshake) .
  • Ele foi projetado para durar muito ; Existem poucos casos em que o fechamento da conexão faz parte do design do protocolo.
  • De uma perspectiva OSI, provavelmente reside em algum lugar da Camada 6
  • Os batimentos cardíacos podem ser configurados para monitorar o status da conexão, pois o TCP não contém nada por si só para fazer isso.
  • É melhor ter um thread dedicado para gerenciar leituras e gravações no soquete TCP subjacente. A maioria, se não todos, os clientes RabbitMQ fazem isso. Nesse sentido, eles geralmente são seguros para threads.
  • Relativamente falando, as conexões são "caras" para criar (devido ao aperto de mão), mas na prática, isso realmente não importa. A maioria dos processos realmente precisará apenas de um objeto de conexão. Porém, você pode manter conexões em um pool, se achar que precisa de mais taxa de transferência do que um único encadeamento / soquete pode fornecer (improvável com a tecnologia de computação atual).

Fatos do canal

Um canal é a sessão do aplicativo que é aberta para cada parte do seu aplicativo se comunicar com o broker RabbitMQ. Ele opera em uma única conexão e representa uma sessão com o broker.

  • Como representa uma parte lógica da lógica do aplicativo, cada canal geralmente existe em seu próprio encadeamento.
  • Normalmente, todos os canais abertos pelo seu aplicativo compartilham uma única conexão (são sessões leves que operam na parte superior da conexão). As conexões são seguras para threads, então isso é bom.
  • A maioria das operações da AMQP ocorre por canais.
  • De uma perspectiva da camada OSI, os canais provavelmente estão em torno da camada 7 .
  • Os canais são projetados para serem transitórios ; parte do design do AMQP é que o canal normalmente é fechado em resposta a um erro (por exemplo, declarar novamente uma fila com parâmetros diferentes antes de excluir a fila existente).
  • Como são transitórios, os canais não devem ser agrupados pelo seu aplicativo.
  • O servidor usa um número inteiro para identificar um canal. Quando o encadeamento que gerencia a conexão recebe um pacote para um canal específico, ele usa esse número para informar ao broker a que canal / sessão o pacote pertence.
  • Os canais geralmente não são seguros para threads, pois não faria sentido compartilhá-los entre os threads. Se você tiver outro encadeamento que precise usar o broker, será necessário um novo canal.

Fatos do Consumidor

Um consumidor é um objeto definido pelo protocolo AMQP. Não é um canal nem uma conexão, sendo algo que seu aplicativo específico usa como uma "caixa de correio" para eliminar mensagens.

  • "Criando um consumidor" significa que você diz ao broker (usando um canal por meio de uma conexão ) que gostaria que as mensagens fossem enviadas a você por esse canal. Em resposta, o broker registrará que você tem um consumidor no canal e começará a enviar mensagens para você.
  • Cada mensagem enviada pela conexão fará referência a um número de canal e um número de consumidor . Dessa forma, o encadeamento de gerenciamento de conexões (nesse caso, dentro da API Java) sabe o que fazer com a mensagem; então, o segmento de manipulação de canal também sabe o que fazer com a mensagem.
  • A implementação do consumidor tem a maior variação possível, porque é literalmente específica do aplicativo. Na minha implementação, optei por executar uma tarefa cada vez que uma mensagem chegava através do consumidor; portanto, eu tinha um encadeamento gerenciando a conexão, um encadeamento gerenciando o canal (e, por extensão, o consumidor) e um ou mais encadeamentos de tarefas para cada mensagem entregue pelo consumidor.
  • Fechar uma conexão fecha todos os canais na conexão. Fechar um canal fecha todos os consumidores no canal. Também é possível cancelar um consumidor (sem fechar o canal). Existem vários casos em que faz sentido executar qualquer uma das três coisas.
  • Normalmente, a implementação de um consumidor em um cliente AMQP alocará um canal dedicado ao consumidor para evitar conflitos com as atividades de outros threads ou códigos (incluindo publicação).

Em termos do que você quer dizer com pool de encadeamentos do consumidor, suspeito que o cliente Java esteja fazendo algo semelhante ao que eu programei (o meu foi baseado no cliente .Net, mas fortemente modificado).

theMayer
fonte
1
"canais não devem ser recolhidas", que é o que eu estou procurando
ospider
"Como são transitórios, os canais não devem ser agrupados pelo seu aplicativo". - você pode esclarecer como chegou a essa conclusão, por favor. Os documentos recomendam o pool de canais se a implementação "um canal por segmento" estiver usando muito recurso, consulte aqui: rabbitmq.com/channels.html#resource-usage
ymas
@ ymas - A documentação a que você está se referindo é especulativa e, na minha opinião, péssima orientação. Estou lendo o código fonte e as especificações do protocolo. Canais não devem ser agrupados, ponto final. Além disso, um canal por thread é orientação com base nesse mesmo princípio. Se você achar que possui tantos canais abertos que o servidor possui recursos limitados, precisará reavaliar sua arquitetura (por exemplo, alterne para um esquema de alta disponibilidade e / ou reduza a simultaneidade).
theMayer
21

Encontrei este artigo que explica todos os aspectos do modelo AMQP, dos quais canal é um. Eu achei muito útil para completar minha compreensão

https://www.rabbitmq.com/tutorials/amqp-concepts.html

Alguns aplicativos precisam de várias conexões com um broker AMQP. No entanto, é indesejável manter muitas conexões TCP abertas ao mesmo tempo, pois isso consome recursos do sistema e dificulta a configuração de firewalls. As conexões AMQP 0-9-1 são multiplexadas com canais que podem ser considerados "conexões leves que compartilham uma única conexão TCP".

Para aplicativos que usam vários threads / processos para processamento, é muito comum abrir um novo canal por thread / processo e não compartilhar canais entre eles.

A comunicação em um canal específico é completamente separada da comunicação em outro canal, portanto, todo método AMQP também carrega um número de canal que os clientes usam para descobrir para qual canal o método se destina (e, portanto, qual manipulador de eventos precisa ser chamado, por exemplo) .

CamW
fonte
4

Há uma relação entre como Uma conexão TCP pode ter vários canais .

Canal : é uma conexão virtual dentro de uma conexão. Ao publicar ou consumir mensagens de uma fila - tudo é feito em um canal. Considerando Conexão : É uma conexão TCP entre seu aplicativo e o broker RabbitMQ.

Na arquitetura multithread, você pode precisar de uma conexão separada por thread. Isso pode levar à subutilização da conexão TCP, além de adicionar sobrecarga ao sistema operacional para estabelecer quantas conexões TCP forem necessárias durante o horário de pico da rede. O desempenho do sistema pode ser drasticamente reduzido. É aqui que o canal se torna útil, ele cria conexões virtuais dentro de uma conexão TCP. Imediatamente reduz a sobrecarga do sistema operacional e também permite realizar operações assíncronas de maneira mais rápida, confiável e simultaneamente. insira a descrição da imagem aqui

Atul Jain
fonte