¿Cuándo utilizar actores en lugar de soluciones de mensajería como WebSphere MQ o Tibco Rendezvous?

106

Ya leí la pregunta y las respuestas de ¿Qué decisiones de diseño favorecerían a los actores de Scala en lugar de a JMS? .

Por lo general, utilizamos soluciones de mensajería que ya existen desde hace años: se usa una implementación JMS como WebSphere MQ o Apache ActiveMQ para la comunicación punto a punto, o Tibco Rendevous para la mensajería de multidifusión.

Son muy estables, probados y ofrecen alta disponibilidad y rendimiento. Sin embargo, la configuración y la configuración parecen mucho más complejas que en Akka.

¿Cuándo y por qué debería usar Akka para algunos casos de uso en los que los productos mencionados anteriormente, WebSphere MQ o ActiveMQ, se han utilizado con éxito hasta ahora? ¿Por qué debería considerar usar Akka en lugar de WebSphere MQ o Tibco RV en mi proyecto futuro?

¿Y cuándo debería evitar Akka? ¿Ofrece la misma alta disponibilidad y rendimiento que las otras soluciones? ¿O es una mala idea comparar Akka con los demás middlewares de mensajería?

¿Quizás también hay otra solución de mensajería en el entorno JVM que debería considerar además de JMS (punto a punto), TibcoRV (multidifusión) y Akka?

Kai Wähner
fuente

Respuestas:

92

En primer lugar, los sistemas de mensajes "más antiguos" (MQ) son más antiguos en implementación, pero son una idea de ingeniería más nueva de: colas persistentes transaccionales . Scala Actors y Akka tal vez sean una implementación más nueva, pero se basan en un modelo de concurrencia anterior de Actors.

Sin embargo, los dos modelos terminan siendo muy similares en la práctica porque ambos se basan en mensajes de eventos: vea mi respuesta a RabbitMQ vs Akka .

Si va a codificar solo para la JVM, entonces Akka probablemente sea una buena opción. De lo contrario, usaría RabbitMQ.

Además, si eres un desarrollador de Scala, Akka debería ser una obviedad. Sin embargo, los enlaces Java de Akka no son muy similares a Java y requieren conversión debido al sistema de tipos de Scala.

Además, en Java, la gente no suele hacer objetos inmutables, lo que le recomiendo que haga para la mensajería. En consecuencia, es muy fácil en Java hacer algo accidentalmente usando Akka que no se escalará (usando objetos mutables para mensajes, confiando en un estado de devolución de llamada de cierre extraño). Con MQ esto no es un problema porque los mensajes siempre se serializan a costa de la velocidad. Con Akka generalmente no lo son.

Akka también escala mejor con una gran cantidad de consumidores que la mayoría de MQ. Esto se debe a que para la mayoría de los clientes MQ (JMS, AMQP), cada conexión de cola requiere un hilo ... por lo tanto, muchas colas == muchos hilos en ejecución permanente. Sin embargo, esto es principalmente un problema del cliente. Creo que ActiveMQ Apollo tiene un despachador sin bloqueo que supuestamente soluciona ese problema para AMQP. El cliente RabbitMQ tiene canales que le permiten combinar varios consumidores, pero todavía hay problemas con una gran cantidad de consumidores que pueden causar interbloqueos o que las conexiones mueran, por lo que generalmente se agregan más subprocesos para evitar este problema.

Dicho esto, la comunicación remota de Akka es bastante nueva y probablemente todavía no ofrece todas las garantías de mensajes confiables y QoS que brindan las colas de mensajes tradicionales (pero eso está cambiando todos los días). También es generalmente de igual a igual, pero creo que es compatible con el servidor a igual, que es generalmente lo que hacen la mayoría de los sistemas MQ (es decir, un solo punto de falla) pero hay sistemas MQ que son de igual a igual (RabbitMQ es servidor a pares).

Finalmente, RabbitMQ y Akka hacen una buena pareja. Puede usar Akka como envoltorio de RabbitMQ, particularmente porque RabbitMQ no lo ayuda a manejar el consumo de mensajes y enrutar los mensajes localmente (en una sola JVM).

Cuando elegir Akka

  • Tenga muchos consumidores (piense en millones).
  • Necesita baja latencia
  • Abierto al modelo de concurrencia de actores

Sistema de ejemplo: un sistema de chat interactivo en tiempo real

Cuando elegir MQ

  • Necesita integrarse con muchos sistemas diferentes (es decir, no JVM)
  • La confiabilidad de los mensajes es más importante que la latencia
  • Me gustaría tener más herramientas y una interfaz de usuario de administración
  • Debido a los puntos anteriores, mejor para tareas de larga duración.
  • Me gustaría utilizar un modelo de simultaneidad diferente al de Actors

Sistema de ejemplo: un sistema de procesamiento por lotes transaccional programado

EDITAR basado en comentarios preocupados

Asumí que el OP estaba preocupado por el procesamiento distribuido que tanto Akka como Message Queues pueden manejar. Supuse que estaba hablando de Akka distribuido . El uso de Akka para la concurrencia local es una comparación de manzanas a naranja con la mayoría de las colas de mensajes . Digo más porque puede aplicar el modelo de cola de mensajes localmente como un modelo de concurrencia (es decir, tema, colas, intercambios) que hacen tanto la biblioteca Reactor como simple-react .

Elegir el modelo / biblioteca de concurrencia adecuado es muy importante para las aplicaciones de baja latencia. Una solución de procesamiento distribuido, como una cola de mensajes, generalmente no es ideal porque el enrutamiento casi siempre se realiza a través del cable, que obviamente es más lento que dentro de la aplicación y, por lo tanto, Akka sería una opción superior. Sin embargo, creo que algunas tecnologías MQ patentadas permiten el enrutamiento local. Además, como mencioné anteriormente, la mayoría de los clientes de MQ son bastante estúpidos con respecto a los subprocesos y no dependen de IO sin bloqueo y tienen un subproceso por conexión / cola / canal ... irónicamente, io sin bloqueo no siempre es de baja latencia, pero generalmente es más recurso eficiente.

Como puede ver, el tema de la programación distribuida y la programación concurrente es bastante grande y cambia todos los días, por lo que mi intención original no era confundir, sino centrarme en un área particular del procesamiento de mensajes distribuidos, que es lo que, en mi opinión, me preocupaba al OP. En términos de simultaneidad, es posible que desee centrar sus búsquedas en la programación "reactiva" (RFP / streams), que es un modelo "más nuevo" pero similar al modelo de actor y al modelo de cola de mensajes, del cual todos estos modelos se pueden combinar generalmente porque están basados ​​en eventos.

Adam Gent
fuente
3
Creo que la respuesta a una pregunta incorrecta no puede ser correcta. No puede comparar una cola de mensajes y un modelo de simultaneidad. Están construidos para resolver COMPLETAMENTE diferentes tareas y tienen en común solo la palabra "mensaje".
Igor S.
2
Bueno, sí y no. Akka es compatible con la mensajería distribuida y puede construir fácilmente un modelo de simultaneidad a partir del paradigma de la cola de mensajes (Reactor de Google Spring). Realmente, la única distinción ahora es que RabbitMQ tiene mensajes duraderos ... oh, espera, Akka también admite eso ahora. Puede decir "Actor" en el título, pero señala explícitamente a Akka, que tiene una superposición masiva con muchos sistemas basados ​​en mensajes (tanto concurrentes como distribuidos).
Adam Gent
4
Por cierto @IgorS. el modelo de simultaneidad que se usa normalmente con las colas de mensajes se llama SEDA (arquitectura dirigida por eventos por etapas). Además de usar Colas, Temas e Intercambios, es un modelo de concurrencia en sí mismo (que resulta ser un modelo distribuido también ... al igual que el modelo de actor). También desprecio cuando alguien dice "pregunta incorrecta" ... además de preguntas inapropiadas, ¿cuándo puede ser incorrecta una pregunta? Es sarcástico y elitista decir algo así.
Adam Gent
1
Nunca dije que fueran intercambiables. Incluso digo que funcionan muy bien juntos y por qué. Pero claramente está hablando de akka distribuido aquí y no akka de la biblioteca de actores. Así es como lo leo. Siéntase libre de editar mi publicación, ya que su punto es válido y podría confundir a otros que tropiecen con la publicación.
Adam Gent
1
Una de las API de Akka Java: ahora está muy limpia, especialmente con JDK 8 lambdas. Sospecho que mejorará si / cuando introduzcan objetos de valor con JDK 10.
Rob Crawford
4

No soy un experto en sistemas de mensajería, pero puedes combinarlos con Akka en tus aplicaciones, obteniendo lo mejor de ambos mundos. Aquí hay un ejemplo que puede resultarle útil para experimentar con Akka y los sistemas de mensajería, en este caso ZeroMQ:

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

Dean Wampler
fuente
6
ZeroMQ no es exactamente un sistema de mensajería. Es más bien una especie de enchufes mejorados. Los sistemas de mensajería completos son mucho más complejos que ZeroMQ. El proyecto en su enlace parece ser solo una envoltura delgada alrededor de ZeroMQ con Akka.
Vladimir Matveev
1

Akka-Camel sería un mejor ejemplo que ZeroMQ: ZeroMQ es una comunicación tcp directa a tcp (por lo tanto, cero, no hay cola de mensajes).

Con AkkaCamel puede abstraer la cola y producir / consumir mensajes directamente de un actor sin ningún código para lidiar con la inserción / extracción de mensajes de la cola de mensajes.

Puede renunciar a akka-zeromq y usar Akka directamente con la comunicación remota. Creo que akka-zeromq se eliminará de la biblioteca central, pero creamos una buena biblioteca zeromq para akka llamada scala-zeromq ( https://github.com/mDialog/scala-zeromq )

Akka tiene un par de casos de uso clave clave:

1) estado mutable

Es más fácil manejar el estado compartido ocultándolo en un actor. Como los actores manejan los mensajes sincrónicamente, puede mantener el estado en un actor y exponer ese campo con alta consistencia a través de la API del actor.

2) Distribución

La concurrencia es gratuita en akka, por lo que dice que realmente se trata de resolver problemas de distribución. Distribución entre máquinas y núcleos. Akka ha incorporado una "transparencia de ubicación" para enviar mensajes por cable. También tiene agrupaciones y patrones asociados para escalar un solo servicio. Esto lo convierte en una muy buena solución para la distribución (por ejemplo, arquitectura de microservicio)

Aquí hay un ejemplo del uso de Akka con ActiveMQ con Akka-Camel (usando 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
fuente