差异消息驱动简单方法调用之间的应用程序

时间:2015-09-04 05:16:44

标签: java concurrency akka quasar

我一直在读一些关于它的内容,发现一些真正搞砸了我想法的库,比如Akka,Quasar,Reactor和Disruptor,Akka和Quasar实现了Actor模式,Disruptor是一个线程间消息传递库和Reactor是根据 。那么使用消息驱动架构而不是简单方法调用的优势是什么呢?

给定一个RabbitMQ队列侦听器,我从方法接收一条消息,决定RabbitMQ消息的类型(NewOrderPayment,...)。

我可以使用Message Driven库。

伪代码:

actor.tell('decider-mailbox',message)

基本上说“我把这个消息放在这里,当你们可以处理它,做它”时等等,直到它被保存。 并且演员再次准备接收另一条消息

但是直接调用像messageHandler.handle(message)这样的方法,会不会更好,更少抽象?

3 个答案:

答案 0 :(得分:3)

Actors Model看起来很像人们一起工作;它基于消息传递,但还有更多内容,我会说并非所有的消息传递模型都是相同的,例如Quasar实际上不仅支持类似Erlang的actor,而且还支持Go-like通道更简单但不提供容错模型(光纤BTW,就像线程一样,但更轻巧,即使没有任何消息传递也可以使用)。

方法/函数遵循严格的,可嵌套的call-return(所以请求 - 响应)规则,通常不涉及任何并发(至少在命令式和非纯函数式语言中)。 / p>

消息传递相反,从广义上讲,允许更松散耦合,因为它不会强制执行请求 - 响应规则并允许通信方同时执行,这也有助于隔离故障和热升级以及一般维护(例如,Actors Model提供这些功能)。消息传递通常也会通过对消息使用更动态的类型来允许更松散的数据合同(对于Actors模型尤其如此,其中每个参与方或 actor 都有一个传入频道,即他的邮箱)。 除此之外,细节很大程度上取决于您正在考虑的消息传递模型/解决方案,例如通信通道可以同步交互部分或具有有限/无限缓冲,允许多个源和/或多个生产者和消费者等。

请注意,RPC实际上是消息传递,但具有严格的请求 - 响应通信规则。

这意味着,视情况而定,其中一种可能更适合您:当您处于回电规则和/或您只是简单时,方法/功能会更好使您的顺序代码更加模块化。当您需要一个可能并发的,自主的“代理”网络时,消息传递会更好,这些代理可以在请求 - 响应规则中进行通信但不一定。

至于演员模型我认为你可以建立更多关于它的见解,例如by reading the first part of this blog post notice :我是帖子的主要作者我是Parallel Universe - 和Quasar - 开发团队的一员:

  

actor模型是容错和高度可伸缩系统的设计模式。参与者是独立的工作者模块,只能通过消息传递与其他参与者进行通信,可以独立于其他参与者而失败,但可以监视其他参与者的失败,并在发生这种情况时采取一些恢复措施。演员是简单,孤立但协调的并发工人。

     

基于演员的设计带来许多好处:

     
      
  • 自适应行为:仅通过消息队列进行交互使得actor松散耦合并允许它们:      
        
    • 隔离故障:邮箱正在解耦消息队列,允许actor在没有服务中断的情况下重新启动。
    •   
    • 管理进化:它们可以在不中断服务的情况下更换演员。
    •   
    • 规范并发:经常接收邮件并丢弃溢出,或者增加邮箱大小可以分别以可靠性或内存使用为代价来最大化并发性。
    •   
    • 调节负载:减少接收呼叫的频率和使用小邮箱会降低并发性并增加延迟,通过actor系统的边界应用反压。
    •   
  •   
  • 最大并发容量:      
        
    • 演员在内存消耗方面非常轻量级   管理开销,所以有可能产生甚至数百万美元   单箱。
    •   
    • 因为演员不共享状态,所以他们可以安全地并行运行。
    •   
  •   
  • 低复杂度:      
        
    • 每个actor都可以通过改变其私有状态来实现有状态行为,而不必担心并发修改。
    •   
    • 演员可以通过选择性地从逻辑而非到达顺序接收来自邮箱的消息来简化其状态转换逻辑。
    •   
  •   

答案 1 :(得分:1)

不同之处在于处理发生在不同的线程中,因此当前的线程已准备好接收和转发下一条消息。当您从当前线程调用处理程序时,它将被阻塞,直到处理完成。

答案 2 :(得分:1)

在某种程度上,这只是定义抽象的问题。有人说最初的面向对象编程实际上应该基于消息传递,并且调用对象上的方法将具有向其发送消息的语义(具有与actor中类似的异步非阻塞行为)。

我们在大多数流行语言中实现OO的方式使其成为现在的样式 - 同步阻止命令"到一个对象,从与调用者相同的执行上下文(线程/进程)控制和运行。这很好,因为它很容易理解,但在设计并发系统时它有其局限性。

理论上,您可以创建一种语法与Java类似的语言,但是给它不同的语义 - 使 object.method(arg)实际上内部类似于 actor.tell( MSG)。有很多习惯用法试图在简单的方法调用后隐藏异步调用和消息传递,但一如既往地取决于用例。

Akka提供了一个很好的新语法,它清楚地表明我们正在做的事情与调用对象上的方法完全不同,部分原因是为了减少混淆并使消息传递更加明确。最后,您正在说明同样的事情 - 您正在向系统中的actor发送消息,但是您使用的约束比直接调用其中一个方法的情况要少。