Quand utiliser des acteurs plutôt que des solutions de messagerie telles que WebSphere MQ ou Tibco Rendezvous?

106

J'ai déjà lu la question et les réponses à Quelles décisions de conception favoriseraient les acteurs de Scala au lieu de JMS? .

Habituellement, nous utilisons des solutions de messagerie qui existent déjà depuis des années: soit une implémentation JMS telle que WebSphere MQ ou Apache ActiveMQ est utilisée pour la communication point à point, soit Tibco Rendevous pour la messagerie multicast.

Ils sont très stables, éprouvés et offrent une disponibilité et des performances élevées. Néanmoins, la configuration et l'installation semblent beaucoup plus complexes que dans Akka.

Quand et pourquoi devrais-je utiliser Akka pour certains cas d'utilisation où les produits susmentionnés - WebSphere MQ ou ActiveMQ - ont été utilisés avec succès jusqu'à présent? Pourquoi devrais-je envisager d'utiliser Akka au lieu de WebSphere MQ ou Tibco RV dans mon futur projet?

Et quand devrais-je éviter Akka? Offre-t-elle la même haute disponibilité et les mêmes performances que les autres solutions? Ou est-ce une mauvaise idée de comparer Akka aux autres middlewares de messagerie?

Peut-être qu'il existe également une autre solution de messagerie dans l'environnement JVM que je devrais envisager en plus de JMS (Point-to-Point), TibcoRV (Multicast) et Akka?

Kai Wähner
la source

Réponses:

92

Tout d'abord, les systèmes de messagerie (MQ) «plus anciens» sont plus anciens dans l'implémentation, mais ils sont une idée plus récente de l'ingénierie: les files d'attente persistantes transactionnelles . Les acteurs Scala et Akka sont peut-être une implémentation plus récente, mais sont construits sur un modèle de concurrence d'accès plus ancien d'acteurs.

Les deux modèles finissent cependant par être très similaires dans la pratique car ils sont tous deux basés sur un message d'événement: voir ma réponse à RabbitMQ vs Akka .

Si vous envisagez de coder uniquement pour la JVM, Akka est probablement un bon choix. Sinon, j'utiliserais RabbitMQ.

De plus, si vous êtes un développeur Scala, Akka devrait être une évidence. Cependant, les liaisons Java d'Akka ne sont pas très Java-ish et nécessitent une conversion en raison du système de type de Scala.

De plus, en Java, les gens ne créent généralement pas d'objets immuables, ce que je vous recommande de faire pour la messagerie. Par conséquent, il est très facile en Java de faire accidentellement quelque chose en utilisant Akka qui ne sera pas mis à l'échelle (en utilisant des objets mutables pour les messages, en s'appuyant sur un état de rappel de fermeture étrange). Avec MQ, ce n'est pas un problème car les messages sont toujours sérialisés au détriment de la vitesse. Avec Akka, ils ne le sont généralement pas.

Akka s'adapte également mieux à un grand nombre de consommateurs que la plupart des MQ. C'est parce que pour la plupart des clients MQ (JMS, AMQP), chaque connexion de file d'attente nécessite un thread ... donc beaucoup de files d'attente == beaucoup de threads en cours d'exécution en permanence. C'est principalement un problème de client. Je pense qu'ActiveMQ Apollo a un répartiteur non bloquant qui résout prétendument ce problème pour AMQP. Le client RabbitMQ dispose de canaux qui vous permettent de combiner plusieurs consommateurs, mais il existe toujours des problèmes avec un grand nombre de consommateurs pouvant entraîner des blocages ou des connexions, de sorte que généralement plus de threads sont ajoutés pour éviter ce problème.

Cela étant dit, la communication à distance d'Akka est plutôt nouvelle et n'offre probablement toujours pas toutes les garanties de messages fiables et la qualité de service que les files d'attente de messages traditionnelles offrent (mais cela change tous les jours). Il est également généralement pair à pair, mais je pense qu'il prend en charge le serveur à pair, ce que font généralement la plupart des systèmes MQ (c'est-à-dire un point de défaillance unique), mais il existe des systèmes MQ peer-to-peer (RabbitMQ est serveur- à pair).

Enfin, RabbitMQ et Akka forment une bonne paire. Vous pouvez utiliser Akka comme wrapper pour RabbitMQ d'autant plus que RabbitMQ ne vous aide pas à gérer la consommation des messages et à acheminer les messages localement (dans une seule JVM).

Quand choisir Akka

  • Avoir beaucoup de consommateurs (pensez à des millions).
  • Besoin d'une faible latence
  • Ouvert au modèle d'accès concurrentiel Actor

Exemple de système: un système de chat interactif en temps réel

Quand choisir MQ

  • Nécessité d'intégrer de nombreux systèmes différents (c'est-à-dire non JVM)
  • La fiabilité des messages est plus importante que la latence
  • Voudrait plus d'outils et d'interface utilisateur d'administration
  • En raison des points précédents, mieux pour les tâches de longue durée
  • Souhaiterait utiliser un modèle de concurrence différent de celui des acteurs

Exemple de système: un système de traitement par lots transactionnel planifié

EDIT sur la base des commentaires concernés

J'ai fait l'hypothèse que l'OP était concerné par le traitement distribué que Akka et Message Queues peuvent gérer. C'est que je suppose qu'il parlait d' Akka distribué . L'utilisation d'Akka pour la concurrence locale est une comparaison pomme à orange avec la plupart des files d'attente de messages . Je dis surtout parce que vous pouvez appliquer le modèle de file d'attente de messages localement en tant que modèle de concurrence (c'est-à-dire sujet, files d'attente, échanges) que font à la fois la bibliothèque Reactor et simple-react .

Choisir le bon modèle / bibliothèque d'accès concurrentiel est très important pour les applications à faible latence. Une solution de traitement distribué telle qu'une file d'attente de messages n'est généralement pas idéale car le routage est presque toujours effectué sur le fil qui est évidemment plus lent que dans l'application et donc Akka serait un choix supérieur. Cependant, je pense que certaines technologies MQ propriétaires permettent un routage local. De plus, comme je l'ai mentionné plus tôt, la plupart des clients MQ sont assez stupides à propos du threading et ne reposent pas sur des E / S non bloquantes et ont un thread par connexion / file d'attente / canal ... ironiquement, io non bloquant n'est pas toujours à faible latence mais est généralement plus de ressources efficace.

Comme vous pouvez le voir, le sujet de la programmation distribuée et de la programmation concurrente est plutôt vaste et changeant tous les jours, donc mon intention initiale n'était pas de confondre mais plutôt de me concentrer sur un domaine particulier du traitement des messages distribués, ce que je pensais que l'OP était concerné. En termes de concurrence d'accès, on peut vouloir concentrer ses recherches sur la programmation «réactive» (RFP / flux) qui est un modèle «plus récent» mais similaire au modèle d'acteur et au modèle de file d'attente de messages dont tous ces modèles peuvent être généralement combinés car ils sont basés sur les événements.

Adam Gent
la source
3
Je pense qu'une réponse à une mauvaise question ne peut pas être juste. Vous ne pouvez pas comparer une file d'attente de messages et un modèle de concurrence. Ils sont construits pour résoudre COMPLÈTEMENT différentes tâches et n'ont en commun que le mot «message».
Igor S.
2
Eh bien oui et non. Akka prend en charge la messagerie distribuée et vous pouvez très facilement créer un modèle de concurrence à partir du paradigme de file d'attente de messages (google Spring's Reactor). Vraiment la seule distinction maintenant est que RabbitMQ a des messages durables .. oh attendez que Akka le supporte maintenant aussi. Il peut dire "Acteur" dans le titre mais souligne explicitement Akka qui a un chevauchement massif avec de nombreux systèmes basés sur des messages (à la fois simultanés et distribués).
Adam Gent
4
BTW @IgorS. le modèle de concurrence généralement utilisé avec les files d'attente de messages est appelé SEDA (architecture pilotée par les événements par étapes). En plus d'utiliser les files d'attente, les sujets et les échanges, il existe un modèle de concurrence en soi (qui se trouve être un modèle distribué également ... tout comme le modèle d'acteur). Je méprise aussi vraiment quand quelqu'un dit "mauvaise question" ... en plus des questions inappropriées, quand une question peut-elle être fausse? C'est sarcastique et élitiste de dire quelque chose comme ça.
Adam Gent
1
Je n'ai jamais dit qu'ils étaient interchangeables. Je dis même qu'ils fonctionnent très bien ensemble et pourquoi. Mais il parle clairement d'akka distribué ici et non d'akka la bibliothèque d'acteurs. C'est comme ça que je l'ai lu. N'hésitez pas à modifier mon message car votre point est valide et pourrait dérouter les autres qui trébucheraient sur le message.
Adam Gent
1
L'une de l'API Java Akka - elle est désormais très propre, en particulier avec les lambdas JDK 8. Je soupçonne que cela ira mieux si / quand ils introduisent des objets de valeur avec JDK 10.
Rob Crawford
4

Je ne suis pas un expert des systèmes de messagerie, mais vous pouvez les combiner avec Akka dans vos applications, en obtenant le meilleur des deux mondes. Voici un exemple que vous pourriez trouver utile pour expérimenter avec Akka et les systèmes de messagerie, dans ce cas ZeroMQ:

https://github.com/zcox/akka-zeromq-java

Dean Wampler
la source
6
ZeroMQ n'est pas exactement un système de messagerie. Il s'agit plutôt d'une sorte de prises améliorées. Les systèmes de messagerie à part entière sont beaucoup plus complexes que ZeroMQ. Le projet au niveau de votre lien semble être juste une mince enveloppe autour de ZeroMQ avec Akka.
Vladimir Matveev
1

Akka-Camel serait un meilleur exemple que ZeroMQ - ZeroMQ est une communication directe TCP vers TCP (donc zéro - il n'y a pas de file d'attente de messages).

Avec AkkaCamel, vous pouvez extraire la file d'attente et produire / consommer des messages directement à partir d'un acteur sans aucun code pour gérer le message de la file d'attente de messages poussant / tirant.

Vous pouvez renoncer à akka-zeromq et utiliser Akka directement avec la communication à distance. Je pense que akka-zeromq est en cours de suppression de la bibliothèque principale, mais nous avons construit une bonne bibliothèque zeromq pour akka appelée scala-zeromq ( https://github.com/mDialog/scala-zeromq )

Akka a quelques cas d'utilisation clés:

1) État mutable

Il est plus facile de gérer l'état partagé en le cachant dans un acteur. Comme les acteurs gèrent les messages de manière synchrone, vous pouvez maintenir l'état d'un acteur et exposer ce champ avec une grande cohérence via l'API d'acteur

2) Distribution

La concurrence est gratuite dans akka, vous dites donc qu'il s'agit vraiment de résoudre les problèmes de distribution. Distribution entre machines et noyaux. Akka a intégré la "transparence de l'emplacement" pour envoyer des messages sur le fil. Il est associé à un clustering et à des modèles pour la mise à l'échelle d'un seul service. Cela en fait une très bonne solution pour la distribution (ex: architecture de micro-services)

Voici un exemple d'utilisation d'Akka avec ActiveMQ avec Akka-Camel (en utilisant Java8)

import akka.actor.Props;
import akka.camel.Camel;
import akka.camel.CamelExtension;
import akka.testkit.TestActorRef;
import akka.testkit.TestProbe;
import org.junit.Ignore;
import org.junit.Test;
import akka.camel.javaapi.UntypedProducerActor;
import akka.camel.javaapi.UntypedConsumerActor;
import static com.rogers.totes.TotesTestFixtures.*;
import org.apache.activemq.camel.component.*;

public class MessagingTest {
    @Test @Ignore
    public void itShouldStoreAMessage() throws Exception{
        String amqUrl = "nio://localhost:61616";
        Camel camel = (Camel) CamelExtension.apply(system);
        camel.context().addComponent("activemq", ActiveMQComponent.activeMQComponent(amqUrl));

        TestProbe probe = TestProbe.apply(system);
        TestActorRef producer = TestActorRef.create(system, Props.create((Producer.class)));
        TestActorRef consumer = TestActorRef.create(system, Props.create((Consumer.class)));
        producer.tell("Produce", probe.ref());

        Thread.sleep(1000);
    }
}

class Producer extends UntypedProducerActor{

    @Override
    public String getEndpointUri() {
        return "activemq:foo.bar";
    }
}

class Consumer extends UntypedConsumerActor{

    @Override
    public String getEndpointUri() {
        return "activemq:foo.bar";
    }

    @Override
    public void onReceive(Object message) throws Exception {
        System.out.println("GOT A MESSAGE!" + message);

    }
}
JasonG
la source