java - ¿Cuándo utilizar actores en lugar de soluciones de mensajería como WebSphere MQ o Tibco Rendezvous?
scala jms (3)
Ya leí la pregunta y las respuestas a ¿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: una implementación de JMS como WebSphere MQ o Apache ActiveMQ se utiliza 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 antes mencionados, WebSphere MQ o ActiveMQ, se han utilizado con éxito hasta el momento? ¿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 incluso comparar Akka con los otros middlewares de mensajería?
Quizás también haya 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.
Akka-Camel sería un mejor ejemplo que ZeroMQ: ZeroMQ es una comunicación directa de tcp 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 manejar el mensaje de cola de mensajes empujando / tirando.
Puede renunciar a akka-zeromq y usar Akka directamente con la comunicación remota. Creo que akka-zeromq se está eliminando 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 clave de uso de núcleo:
1) estado mutable
Es más fácil manejar el estado compartido escondiéndolo en un actor. A medida que los actores manejan los mensajes de forma sincrónica, 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 dices que realmente se trata de resolver problemas de distribución. Distribución en máquinas y núcleos. Akka ha incorporado una "transparencia de ubicación" para enviar mensajes a través del cable. También tiene clústeres y patrones asociados para escalar un solo servicio. Esto lo convierte en una muy buena solución para la distribución (ej. Arquitectura de micro-servicio)
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);
}
}
En primer lugar, los sistemas de mensajes "antiguos" (MQ) son más antiguos en la implementación pero son más nuevos en la idea de ingeniería de: colas transaccionales persistentes . Scala Actors y Akka tal vez una implementación más nueva, pero se basan en un modelo de concurrencia más antiguo de Actores.
Sin embargo, los dos modelos terminan siendo muy similares en la práctica porque ambos se basan en mensajes de eventos: ver mi respuesta a RabbitMQ vs Akka .
Si vas a codificar solo para la JVM, entonces Akka es probablemente una buena opción. De lo contrario, usaría RabbitMQ.
Además, si eres un desarrollador de Scala, entonces Akka no debería ser obvio. Sin embargo, las vinculaciones Java de Akka no son muy Java-ish y requieren conversión debido al sistema de tipos de Scala.
También en Java las personas no suelen hacer objetos inmutables que recomiendo que hagas para enviar mensajes. En consecuencia, es muy fácil en Java hacer algo accidentalmente usando Akka que no se escale (usando objetos mutables para mensajes, dependiendo del extraño estado de devolución de llamadas). 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 se 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 de MQ (JMS, AMQP) cada conexión de cola requiere un hilo ... por lo tanto, muchas colas == lotes de hilos que se ejecutan permanentemente. Sin embargo, esto es principalmente un problema del cliente. Creo que ActiveMQ Apollo tiene un despachador no bloqueador que supuestamente soluciona ese problema para AMQP. El cliente RabbitMQ tiene canales que le permiten combinar múltiples consumidores, pero todavía hay problemas con la gran cantidad de consumidores que pueden causar la muerte de interbloqueos o conexiones, por lo que generalmente se agregan más hilos para evitar este problema.
Dicho esto, la comunicación remota de Akka es bastante nueva y probablemente todavía no ofrezca todas las garantías de mensajes confiables y QoS que ofrecen las colas de mensajes tradicionales (pero eso está cambiando todos los días). También es generalmente peer-to-peer pero creo que es compatible con servidor a peer, que generalmente es lo que hacen la mayoría de los sistemas MQ (es decir, punto único de falla) pero hay sistemas MQ que son peer-to-peer (RabbitMQ es server- a la par).
Finalmente, RabbitMQ y Akka hacen un buen par. Puede usar Akka como envoltorio para RabbitMQ, especialmente porque RabbitMQ no lo ayuda a manejar el consumo de mensajes y enrutar los mensajes localmente (en una sola JVM).
Cuándo elegir Akka
- Tener muchos consumidores (pensar millones).
- Necesita baja latencia
- Abierto al modelo de concurrencia Actor
Sistema de ejemplo: un sistema interactivo de chat en tiempo real
Cuándo elegir MQ
- Necesidad de integrarse con muchos sistemas diferentes (es decir, sin JVM)
- La confiabilidad del mensaje es más importante que la latencia
- Quisiera más herramientas y UI de administrador
- Debido a los puntos anteriores, mejor para las tareas de larga ejecución
- Me gustaría utilizar un modelo de concurrencia diferente que los Actores
Sistema de ejemplo: un sistema de procesamiento por lotes transaccional programado
EDIT basado en comentarios preocupados
Supuse que el PO estaba relacionado con el procesamiento distribuido que tanto Akka como Message Queues pueden manejar. Es decir, asumí que estaba hablando de Akka distribuido . Usar Akka para la concurrencia local es una comparación de manzanas a naranjas para 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 de Reactor como simple-react .
Elegir el modelo / biblioteca de concurrencia correcto es muy importante para 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 elección superior. Sin embargo, creo que algunas tecnologías patentadas de MQ permiten el enrutamiento local. Además, como mencioné anteriormente, la mayoría de los clientes de MQ son bastante estúpidos con el subprocesamiento y no dependen de E / S no bloqueantes y tienen un hilo por conexión / cola / canal ... irónicamente, el no bloqueo no siempre es de baja latencia, pero generalmente es más 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 de procesamiento de mensajes distribuidos, que es lo que yo pensaba que le preocupaba al OP. En términos de concurrencia uno podría querer enfocar sus búsquedas en programación "reactiva" (RFP / streams) que es un modelo "más nuevo" pero similar al modelo de actor y modelo de cola de mensajes de los cuales todos estos modelos se pueden combinar generalmente porque están basados en eventos.
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 ser útil para experimentar con Akka y los sistemas de mensajería, en este caso ZeroMQ: