Design e nomeação de filas

Algumas regras sobre como organizar pontos, filas e como nomeá-los corretamente para torná-lo conveniente.

| exchange | type | binding_queue | binding_key | |-------------------------------------------------------| | user.write | topic | user.created.app2 | user.created | 

Os conceitos
O AMQP (Advanced Message Queuing Protocol) é um protocolo aberto para transferir mensagens entre componentes do sistema.
Fornecedor (editores / produtor) - um programa que envia mensagens.
Assinante (Consumidor) - um programa que aceita mensagens. Normalmente, o assinante está em um estado de espera de mensagem.
Fila - uma fila de mensagens.
Ponto de Troca (Troca) - O ponto de troca inicial da fila, envolvida no roteamento.

Regra 1


Cada fila deve representar apenas um tipo de trabalho. Não misture tipos diferentes de mensagens na mesma fila. E quando essa regra é respeitada, podemos nomear claramente a fila de tarefas apresentada a eles.

Regra 2


Evite reenviar mensagens para a fila. Se você achar que seu assinante está tentando reenviar mensagens para outras filas sem processamento real, provavelmente algo não foi projetado corretamente. O roteamento é de responsabilidade dos pontos de troca, não das filas.

Regra 3


Os fornecedores não precisam saber nada sobre filas. Uma das principais idéias do AMQP é a divisão de responsabilidades entre pontos e filas, para que os fornecedores não precisem cuidar para que a mensagem chegue ao assinante.

Exemplos e soluções


Suponha que você deseje projetar pontos e filas para eventos de registro relacionados “personalizados”. Os eventos de gravação serão disparados em um ou mais aplicativos e essas mensagens serão usadas por outros aplicativos.

 | object | event | |------------------| | user | created | | user | updated | | user | deleted | 

A primeira pergunta que geralmente é feita são os vários eventos de um objeto (o objeto "usuário" neste exemplo). Devo usar um ponto de troca para publicar todos os três eventos ou usar 3 pontos separados para cada evento? Ou, resumindo, um ponto de troca ou muitos?

Antes de responder a essa pergunta, quero fazer outra pergunta: precisamos mesmo de um ponto separado para este caso? E se abstrairmos todos os três tipos de eventos como um evento de "gravação" cujos subtipos são "criados", "atualizados" e "excluídos"?

 | object | event | sub-type | |-----------------------------| | user | write | created | | user | write | updated | | user | write | deleted | 

Solução 1


A solução mais simples é criar a fila "user.write" e publicar todas as mensagens dos eventos de gravação do usuário nessa fila por meio do ponto de troca global.

Decisão 2


A solução mais simples não pode funcionar quando há um segundo aplicativo (com uma lógica de processamento diferente) que deseja assinar qualquer mensagem publicada na fila. Quando vários aplicativos são assinados, precisamos de pelo menos um ponto com o tipo “fanout” com ligações a várias filas. Assim, as mensagens são enviadas para o ponto e as duplicam em cada fila. Cada fila representa um trabalho de processamento para cada aplicativo.

 | queue | subscriber | |-------------------------------| | user.write.app1 | app1 | | user.write.app2 | app2 | | exchange | type | binding_queue | |---------------------------------------| | user.write | fanout | user.write.app1 | | user.write | fanout | user.write.app2 | 

A segunda solução funciona bem se todo assinante realmente deseja lidar com todos os subtipos de eventos "user.write". Por exemplo, se o aplicativo do assinante for projetado para simplesmente armazenar um log de transações.

Por outro lado, não é muito bom quando alguns assinantes estão fora da sua organização e você deseja notificá-los apenas sobre determinados eventos específicos, por exemplo, o app2 deve receber uma mensagem sobre a criação do usuário e não deve saber sobre atualizar e excluir eventos.

Decisão 3


Para resolver o problema acima, precisamos extrair o evento "user.created" do tipo "user.write". Um ponto de troca com um tipo de tópico pode nos ajudar. Ao publicar mensagens, usaremos user.created / user.updated / user.deleted como chaves de roteamento em um ponto, para que possamos colocar a chave de comunicação "user". Na fila "user.write.app1" e a chave de comunicação "user.created" na fila "user.created.app2".

 | queue | subscriber | |---------------------------------| | user.write.app1 | app1 | | user.created.app2 | app2 | | exchange | type | binding_queue | binding_key | |-------------------------------------------------------| | user.write | topic | user.write.app1 | user.* | | user.write | topic | user.created.app2 | user.created | 

Decisão 4


O tipo de tópico do tópico do ponto de troca é mais flexível caso haja potencialmente mais tipos de eventos. Mas se você souber claramente o número exato de eventos, também poderá usar o tipo "direto" para melhorar o desempenho.

 | queue | subscriber | |---------------------------------| | user.write.app1 | app1 | | user.created.app2 | app2 | | exchange | type | binding_queue | binding_key | |--------------------------------------------------------| | user.write | direct | user.write.app1 | user.created | | user.write | direct | user.write.app1 | user.updated | | user.write | direct | user.write.app1 | user.deleted | | user.write | direct | user.created.app2 | user.created | 

Voltamos à pergunta "um ponto, ou muito?". Desde que todas as soluções usem apenas um ponto, elas funcionam bem, nada de ruim. Em que situações podemos precisar de vários pontos?

Decisão 5


Vejamos um exemplo quando, além dos eventos criados, atualizados e excluídos descritos acima, temos outro grupo de eventos: entrada e saída - um grupo de eventos que descreve o "comportamento do usuário" em vez de "gravação de dados". Para diferentes grupos de eventos, podem ser necessárias estratégias de roteamento completamente diferentes e concordar com as chaves e os nomes das filas e, para isso, são necessários pontos de troca separados.

 | queue | subscriber | |----------------------------------| | user.write.app1 | app1 | | user.created.app2 | app2 | | user.behavior.app3 | app3 | | exchange | type | binding_queue | binding_key | |--------------------------------------------------------------| | user.write | topic | user.write.app1 | user.* | | user.write | topic | user.created.app2 | user.created | | user.behavior | topic | user.behavior.app3 | user.* | 

Tradução gratuita do artigo Troca RabbitMQ Exchange e Queue Design Trade-off .

Source: https://habr.com/ru/post/pt443722/


All Articles