何时使用参与者而不是消息解决scheme(如WebSphere MQ或Tibco Rendezvous)?

我已经阅读过什么样的devise决定会赞成Scala的Actor而不是JMS的问题和答案? 。

通常,我们使用已存在多年的消息传递解决scheme:使用诸如WebSphere MQ或Apache ActiveMQ之类的JMS实现进行点对点通信,或者使用Tibco Rendevous进行多播消息传递。

它们非常稳定,经过validation,可提供高可用性和高性能。 尽pipe如此,configuration和设置似乎比阿卡更复杂。

何时以及为什么我应该使用Akka来处理上述产品(WebSphere MQ或ActiveMQ)已经成功使用的情况? 为什么我应该在未来的项目中考虑使用Akka而不是WebSphere MQ或Tibco RV?

什么时候我应该避免阿卡? 它是否提供与其他解决scheme相同的高可用性和性能? 或者将Akka与其他消息中间件进行比较,这是不是一个好主意?

也许除了JMS(点对点),TibcoRV(多播)和Akka之外,JVM环境中还应该考虑另一个消息传递解决scheme?

首先,“较旧的”消息系统(MQ)在实现方面较老,但在工程思想上更新一些: 事务持久队列 。 Scala Actors和Akka可能是一个更新的实现,但是build立在一个较老的Actors的并发模型上。

然而,这两种模式在实践中最终非常相似,因为它们都是基于事件消息的:查看我对RabbitMQ和Akka的回答。

如果你打算只为JVM编写代码,那么Akka可能是一个不错的select。 否则,我会使用RabbitMQ。

另外如果你是一个Scala开发者,那么Akka应该是一个不容易的事情。 然而,Akka的Java绑定不是非常Java的,因为Scala的types系统,需要强制转换。

另外在Java中,人们通常不会制造我build议你做消息传递的不可变对象。 因此,在Java中非常容易地使用Akka,不会扩展(使用可变对象的消息,依靠奇怪的closurescallback状态)。 使用MQ,这不是一个问题,因为消息总是以代价的速度进行序列化。 阿卡他们一般不是。

与大多数MQ相比,Akka在大量消费者方面的规模也更好。 这是因为对于大多数MQ(JMS,AMQP)客户端,每个队列连接都需要一个线程…因此大量的队列==大量永久运行的线程。 但这主要是客户端问题。 我认为ActiveMQ Apollo有一个非阻塞的调度程序,据称是为AMQP修复这个问题。 RabbitMQ客户端有一些渠道可以让你组合多个消费者,但是仍然有大量消费者可能导致死锁或连接死亡的问题,所以通常会增加更多的线程来避免这个问题。

这就是说, 阿卡的远程处理相当新颖,可能还没有提供传统消息队列提供的所有可靠的消息保证和QoS(但是每天都在改变)。 它也一般是对等的,但我认为支持服务器间通常是大多数MQ系统所做的(即单点故障),但是有MQ系统是点对点的(RabbitMQ是服务器端的,对等)。

最后RabbitMQ和Akka实际上是一个很好的组合。 您可以使用Akka作为RabbitMQ的包装,因为RabbitMQ不能帮助您处理消息的消耗并在本地(在单个JVM中)路由消息。

什么时候select阿卡

  • 有很多消费者(认为数以百万计)。
  • 需要低延迟
  • 打开到Actor并发模型

示例系统:一个交互式实时聊天系统

何时selectMQ

  • 需要集成许多不同的系统(即非JVM)
  • 消息的可靠性比延迟更重要
  • 想要更多的工具和pipe理界面
  • 由于以前的点更适合长时间运行的任务
  • 希望使用与Actors不同的并发模型

示例系统:预定的事务批处理系统

编辑根据有关意见

我假定OP是关心Akka和Message Queue可以处理的分布式处理。 那是我以为他在谈论分发阿卡 。 使用Akka进行本地并发是一个与大多数消息队列进行橙色比较的苹果 。 我说最多的是因为你可以在本地应用消息队列模型作为一个并发模型(即主题,队列,交换), 反应堆库和简单反应都可以做到。

select正确的并发模型/库对于低延迟应用程序非常重要。 消息队列等分布式处理解决scheme通常并不理想,因为路由几乎总是通过线路完成的,而线路明显比应用内部的要慢,因此Akka将是最好的select。 不过,我相信一些专有的MQ技术允许本地路由。 也正如我前面提到的,大多数MQ客户端是非常愚蠢的线程,并不依赖于非阻塞IO,并有每个连接/队列/通道的线程…讽刺非阻塞io并不总是低延迟,但通常更多的资源高效。

正如你所看到的,分布式编程和并发编程的主题是相当大的,每天都在变化,所以我的初衷并不是混淆,而是集中在分布式消息处理的一个特定领域,这正是OP所关心的。 就并发性而言,人们可能希望把他们的search集中在“react native”编程(RFP /stream)上,这是一种“更新”但类似于模型的动作者模型和消息队列模型,所有这些模型通常可以组合在一起,是基于事件的。

我不是消息传递系统方面的专家,但是你可以在你的应用中将他们与Akka结合起来,从而获得两全其美的好处。 下面是一个例子,你可能会发现有用的实验Akka和消息系统,在这种情况下ZeroMQ:

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

Akka-Camel将是比ZeroMQ更好的例子 – ZeroMQ是一个直接的tcp到tcp通信(因此为零 – 没有消息队列)。

使用AkkaCamel,您可以抽象出队列,并直接从一个actor中产生/使用消息,而不需要任何代码来处理消息队列消息推/拉。

您可以放弃akka-zeromq并直接使用Akka进行远程处理。 我认为akka-zeromq被从核心库中删除,但是我们为akka构build了一个名为scala-zeromq的好的zeromq库( https://github.com/mDialog/scala-zeromq

Akka有几个关键的核心用例:

1)可变状态

隐藏在演员中处理共享状态更容易。 由于actor同步处理消息,你可以在actor中保持状态,并通过actor API高度一致地暴露该字段

2)分配

并发在akka中是免费的,所以你说它是真正解决分发问题。 跨机器和核心分布。 Akka已经build立了“位置透明”来通过电报发送消息。 它还具有集群和模式,可以扩展单个服务。 这使得它成为一个非常好的分配解决scheme(如微服务架构)

这是一个使用Akka与Akka-Camel的ActiveMQ(使用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); } }