RabbitMQ-ordre de livraison des messages

je dois choisir un nouveau courtier pour mon nouveau projet.

cette fois, j'ai besoin d'une file d'attente évolutive qui supporte pub/sub, et garder l'ordre des messages est un must.

j'ai lu le commentaire D'Alexis: il écrit:

"en effet, nous pensons que RabbitMQ fournit des commandes plus fortes que Kafka "

j'ai lu le message de commande de la section de rabbitmq docs:

" les Messages peuvent être retournés à la file d'attente en utilisant les méthodes AMQP qui présentent un requeue paramètre (de base.récupérer, de base.rejeter et de base.nack), ou en raison d'un canal fermeture en tenant des messages non reconnus...Avec la version 2.7.0 et plus il est encore possible pour les consommateurs d'observer les messages de commande si la file d'attente a plusieurs abonnés. Cela est dû aux actions de autres Abonnés qui peuvent demander des messages. À partir de la point de vue de la file d'attente les messages sont toujours placés dans l'ordre de publication."

si je dois traiter des messages selon leur commande, Je ne peux utiliser rabbitMQ avec une file d'attente exclusive à chaque consommateur?

le RabbitMQ est-il toujours considéré comme une bonne solution pour la mise en file d'attente des messages commandés?

39
demandé sur durrrr 2014-01-26 16:26:50

4 réponses

bien, regardons de plus près le scénario que vous décrivez ci-dessus. Je pense qu'il est important de coller la documentation immédiatement avant l'extrait de votre question pour fournir le contexte:

la section 4.7 de la spécification de base 0-9-1 de L'AMQP explique conditions dans lesquelles la commande est garantie: un canal, en passant par un échange et une file d'attente et un canal sortant sera reçus dans le même ordre qu'ils ont été envoyé. RabbitMQ offre des garanties plus solides depuis la version 2.7.0.

Les Messages

peuvent être retournés à la file d'attente en utilisant les méthodes AMQP un paramètre requeue (basic.récupérer, de base.rejeter et de base.nack), ou en raison d'une fermeture de canal tout en tenant des messages non reconnus. Tout d' ces scénarios causé des messages requeued à l'arrière de la file d'attente pour les versions de RabbitMQ plus tôt que 2.7.0. De la sortie de RabbitMQ 2.7.0, les messages sont toujours placés dans la file d'attente dans l'ordre de publication , même en présence d'une demande ou d'une fermeture de canal. (non souligné dans l'original)

il est donc clair que RabbitMQ, à partir de la version 2.7.0, apporte une amélioration assez importante par rapport à la spécification initiale de L'AMQP en ce qui concerne la commande des messages.

avec plusieurs consommateurs (parallèles), l'ordre de traitement ne peut pas être garanti.

Le troisième paragraphe (collé dans la question) donne un avertissement, que je vais paraphraser: "si vous avez plusieurs processeurs dans la file d'attente, il n'y a plus de garantie que les messages seront traités dans l'ordre."Tout ce qu'ils disent ici, c'est que RabbitMQ ne peut pas défier les lois des mathématiques.

considérez une ligne de clients à une banque. Cette banque est fière d'aider les clients dans l'ordre dans lequel ils sont venus à la banque. Les clients s'alignent dans une file d'attente, et sont servis par le prochain des 3 guichets disponibles.

ce matin, il s'est produit que les trois caissières sont devenues disponibles en même temps, et les 3 clients suivants approchés. Soudain, le premier des trois caissiers est tombé gravement malade et n'a pas pu finir de servir le premier client de la ligne. Au moment où cela s'est produit, teller 2 avait terminé avec le client 2 et teller 3 avait déjà commencé à servir le client 3.

deux choses peuvent arriver. (1) le premier client en ligne peut revenir à la tête de la ligne ou (2) le premier client peut anticiper le troisième client, ce qui fait que le caissier cesse de travailler sur le troisième client et commence à travailler sur le premier. Ce type de logique de préemption n'est pas supporté par RabbitMQ, ni par aucun autre courtier de messages que je connaisse. Dans un cas comme dans l'autre, le premier client ne finit pas par être aidé le premier - Le deuxième client le fait, étant chanceux assez pour obtenir un bon, teller rapide sur la batte. La seule façon de garantir les clients sont aidés dans l'ordre est d'avoir un guichet aider les clients un à la fois, ce qui causera des problèmes majeurs de service à la clientèle pour la banque.

j'espère que cela aide à illustrer le problème que vous posez sur. Il n'est pas possible de s'assurer que les messages sont traités dans l'ordre dans tous les cas possibles, étant donné que vous avez plusieurs consommateurs. Ça n'a pas d'importance si vous avez plusieurs files d'attente, plusieurs consommateurs exclusifs, courtiers différents, etc. - il n'y a aucun moyen de garantir a priori que les messages sont répondus dans l'ordre avec des consommateurs multiples. Mais RabbitMQ fera de son mieux.

98
répondu theMayer 2017-11-27 20:02:28

L'ordre des messages est conservé à Kafka, mais seulement dans les partitions plutôt que globalement. Si vos données ont besoin à la fois d'un ordre global et de partitions, cela rend les choses difficiles. Toutefois, si vous avez juste besoin de s'assurer que tous les événements pour le même utilisateur, etc... finissez dans la même partition pour qu'ils soient correctement ordonnés, vous pouvez le faire. Le producteur est responsable de la partition qu'ils écrivent, donc si vous êtes en mesure d'logiquement partition de vos données, cela peut être préférable.

6
répondu tyler neely 2015-03-02 14:24:39

je pense qu'il y a deux choses dans cette question qui ne sont pas similaires, l'ordre de consommation et l'ordre de transformation.

les Files d'attente de messages peuvent-dans une certaine mesure - vous donner une garantie que les messages seront consommés dans l'ordre, ils ne peuvent pas, cependant, vous donner des garanties sur l'ordre de leur traitement.

la principale différence ici est qu'il y a certains aspects du traitement des messages qui ne peuvent pas être déterminés au moment de la consommation, par exemple:

  • comme mentionné un consommateur peut échouer pendant le traitement, ici l'ordre de consommation du message était correct, cependant, le consommateur n'a pas réussi à le traiter correctement, ce qui le fera revenir à la file d'attente, et jusqu'à présent l'ordre de consommation est toujours intact, mais nous ne savons pas comment l'ordre de traitement est maintenant

  • Si par "traitement", on entend que le message est maintenant jeté et terminé le traitement de complètement, alors considérez le cas où votre temps de traitement n'est pas linéaire, en d'autres termes le traitement d'un message prend plus de temps qu'un autre, donc si le message 3 prend plus de temps dans le traitement que prévu, alors les messages 4 et 5 pourraient être consommés et finir le traitement avant que le message 3 ne

ainsi, même si vous avez réussi à obtenir le message de retour à l'avant de la file d'attente (qui par la voie viole l'ordre de consommation), vous ne pouvez toujours pas garantir que tous les messages avant le prochain message ont terminé leur traitement.

si vous voulez assurer l'ordre de traitement alors:

  1. Ont seulement 1 consommateur exemple à tous les temps
  2. ou ne pas utiliser une file d'attente de messagerie et faire le traitement dans une méthode de blocage synchrone, ce qui pourrait sembler mauvais, mais dans de nombreux cas et les exigences de l'entreprise est tout à fait valide et parfois même critique
0
répondu engma 2018-02-01 02:21:52

il y a de bonnes façons de garantir l'ordre des messages dans les souscriptions RabbitMQ.

si vous utilisez plusieurs consommateurs, ils traiteront le message en utilisant un ExecutorService partagé . Voir aussi ConnectionFactory.setSharedExecutor(...) . Vous pourriez mettre un Executors.newSingleThreadExecutor() .

si vous utilisez un Consumer avec une file d'attente unique, vous pouvez lier cette file d'attente en utilisant plusieurs bindingKeys (ils peuvent avoir des jokers). Les messages seront placés dans le file d'attente dans le même ordre qu'elles ont été reçues par le courtier de messages.

par exemple, vous avez un seul éditeur qui publie des messages lorsque l'ordre est important:

try (Connection connection2 = factory.newConnection();
        Channel channel2 = connection.createChannel()) {
    // publish messages alternating to two different topics
    for (int i = 0; i < messageCount; i++) {
        final String routingKey = i % 2 == 0 ? routingEven : routingOdd;
        channel2.basicPublish(exchange, routingKey, null, ("Hello" + i).getBytes(UTF_8));
    }
}

vous pourriez maintenant vouloir recevoir des messages des deux topics dans une file dans le même ordre qu'ils ont été publiés:

// declare a queue for the consumer
final String queueName = channel.queueDeclare().getQueue();

// we bind to queue with the two different routingKeys
final String routingEven = "even";
final String routingOdd = "odd";
channel.queueBind(queueName, exchange, routingEven);
channel.queueBind(queueName, exchange, routingOdd);
channel.basicConsume(queueName, true, new DefaultConsumer(channel) { ... });

Le Consumer va maintenant recevoir les messages dans la l'ordre qu'ils ont été publiés, indépendamment du fait que vous avez utilisé différents sujets .

il y a quelques bons tutoriels de 5 minutes dans la documentation de RabbitMQ qui pourraient être utiles: https://www.rabbitmq.com/tutorials/tutorial-five-java.html

0
répondu benez 2018-09-12 14:18:15