web-dev-qa-db-fra.com

RabbitMQ: message persistant avec échange de sujets

Je suis très nouveau sur RabbitMQ.

J'ai mis en place un échange "thématique". Les consommateurs peuvent être lancés après l'éditeur. J'aimerais que les consommateurs puissent recevoir des messages qui ont été envoyés avant qu'ils ne soient activés et qui n'ont pas encore été consommés.

L'échange est configuré avec les paramètres suivants:

exchange_type => 'topic'
durable => 1
auto_delete => 0
passive => 0

Les messages sont publiés avec ce paramètre:

delivery_mode => 2

Les consommateurs utilisent get () pour récupérer les messages de l'échange.

Malheureusement, tout message publié avant la fermeture d'un client est perdu. J'ai utilisé différentes combinaisons.

Je suppose que mon problème est que l'échange ne contient pas de messages. J'ai peut-être besoin d'une file d'attente entre l'éditeur et la file d'attente. Mais cela ne semble pas fonctionner avec un échange de "sujet" où les messages sont acheminés par une clé.

Toute idée de la marche à suivre. J'utilise la liaison Perl Net :: RabbitMQ (cela n'a pas d'importance) et RabbitMQ 2.2.0.

62
Julien

Vous avez besoin d'une file d'attente durable pour stocker les messages si aucun consommateur connecté n'est disponible pour traiter les messages au moment de leur publication.

Un échange ne stocke pas de messages, mais une file d'attente peut. La partie déroutante est que les échanges peuvent être marqués comme "durables", mais cela signifie vraiment que l'échange lui-même sera toujours là si vous redémarrez votre courtier , mais cela signifie pas que tous les messages envoyés à cet échange sont automatiquement persistés.

Cela étant, voici deux options:

  1. Effectuez ne étape administrative avant de démarrer vos éditeurs pour créer vous-même la ou les files d'attente. Vous pouvez utiliser l'interface utilisateur Web ou les outils de ligne de commande pour ce faire. Assurez-vous de le créer en tant que file d'attente durable afin qu'il stocke tous les messages qui lui sont acheminés même s'il n'y a pas de consommateurs actifs.
  2. En supposant que vos consommateurs sont codés pour toujours déclarer (et donc créer automatiquement) leurs échanges et leurs files d'attente au démarrage (et qu'ils les déclarent durables), juste exécutez tous vos consommateurs au moins une fois avant de démarrer tout éditeur . Cela garantira que toutes vos files d'attente seront créées correctement. Vous pouvez ensuite arrêter les consommateurs jusqu'à ce qu'ils soient vraiment nécessaires, car les files d'attente stockeront de manière persistante tous les futurs messages qui leur seront acheminés.

J'irais pour # 1. Il peut ne pas y avoir beaucoup d'étapes à effectuer et vous pouvez toujours écrire les étapes requises afin qu'elles puissent être répétées. De plus, si tous vos consommateurs vont tirer de la même file d'attente unique (plutôt que d'avoir une file d'attente dédiée chacun), c'est vraiment une charge administrative minimale.

Les files d'attente doivent être gérées et contrôlées correctement. Sinon, vous pourriez vous retrouver avec des consommateurs voyous déclarant des files d'attente durables, les utilisant pendant quelques minutes mais jamais plus. Peu de temps après, vous aurez une file d'attente en croissance permanente sans rien réduire sa taille et une apocalypse de courtier imminente.

65
Brian Kelly

Comme mentionné par Brian, un échange ne stocke pas de messages et est principalement responsable du routage des messages vers un ou plusieurs autres échanges ou files d'attente. Si l'échange n'est pas lié à une file d'attente, tous les messages envoyés à cet échange seront "perdus"

Vous ne devriez pas avoir besoin de déclarer des files d'attente client fixes dans le script de l'éditeur car cela peut ne pas être évolutif. Les files d'attente peuvent être créées dynamiquement par vos éditeurs et acheminées en interne à l'aide de la liaison échange à échange.

RabbitMQ prend en charge les liaisons d'échange à échange qui permettront la flexibilité de la topologie, le découplage et d'autres avantages. Vous pouvez en savoir plus ici sur RabbitMQ Exchange to Exchange Bindings [AMPQ]

RabbitMQ Exchange To Exchange Binding

Example Topology

Exemple Python code pour créer une liaison échange à échange avec persistance si aucun consommateur n'est présent en utilisant la file d'attente.

#!/usr/bin/env python
import pika
import sys


connection = pika.BlockingConnection(pika.ConnectionParameters(
Host='localhost'))
channel = connection.channel()


#Declares the entry exchange to be used by all producers to send messages. Could be external producers as well
channel.exchange_declare(exchange='data_gateway',
exchange_type='fanout',
durable=True,
auto_delete=False)

#Declares the processing exchange to be used.Routes messages to various queues. For internal use only
channel.exchange_declare(exchange='data_distributor',
exchange_type='topic',
durable=True,
auto_delete=False)

#Binds the external/producer facing exchange to the internal exchange
channel.exchange_bind(destination='data_distributor',source='data_gateway')

##Create Durable Queues binded to the data_distributor exchange
channel.queue_declare(queue='trade_db',durable=True)
channel.queue_declare(queue='trade_stream_service',durable=True)
channel.queue_declare(queue='ticker_db',durable=True)
channel.queue_declare(queue='ticker_stream_service',durable=True)
channel.queue_declare(queue='orderbook_db',durable=True)
channel.queue_declare(queue='orderbook_stream_service',durable=True)

#Bind queues to exchanges and correct routing key. Allows for messages to be saved when no consumer is present
channel.queue_bind(queue='orderbook_db',exchange='data_distributor',routing_key='*.*.orderbook')
channel.queue_bind(queue='orderbook_stream_service',exchange='data_distributor',routing_key='*.*.orderbook')
channel.queue_bind(queue='ticker_db',exchange='data_distributor',routing_key='*.*.ticker')
channel.queue_bind(queue='ticker_stream_service',exchange='data_distributor',routing_key='*.*.ticker')
channel.queue_bind(queue='trade_db',exchange='data_distributor',routing_key='*.*.trade')
channel.queue_bind(queue='trade_stream_service',exchange='data_distributor',routing_key='*.*.trade')
19
Skillachie