actor模型是用于容错和高度可扩展系统的设计模式。 角色是独立的工作程序模块,仅通过消息传递与其他角色进行通信,可以与其他角色隔离而失败,但是可以监视其他角色的故障并在发生这种情况时采取一些恢复措施。 参与者是简单,孤立但又协调的并发工作者。
基于演员的设计带来许多好处:
- 自适应行为 :仅通过消息队列进行交互会使参与者松散耦合,并允许他们:
- 隔离故障 :邮箱将消息队列解耦 ,使参与者可以在不中断服务的情况下重新启动。
- 最大并发容量 :
- Actor在内存消耗和管理开销方面都非常轻巧 ,因此可以在一个盒子中生成甚至数百万个。
- 低复杂度 :
- 每个参与者都可以通过更改其私有状态来实现有状态行为,而不必担心并发修改。
凭借Erlang ,演员模型得到了广泛认可,并成功实现了关键生产系统中的目标。
这是针对JVM的两个参与者库的比较回顾:我们自己的Quasar和Typesafe的Akka 。
类星体
Quasar是一个用于简单,轻量级JVM并发的开源库,该库在JVM上实现了真正的轻量级线程(AKA光纤)。 Quasar光纤的行为与普通Java线程一样,除了它们几乎没有内存和任务切换开销之外,因此您可以在单个JVM中轻松产生数十万甚至上百万的光纤。 Quasar还提供了以Go语言提供的模式为模型的光纤间通信通道,并带有通道选择器。 它还包含actor模型的完整实现,该模型以Erlang为蓝本。
尽管本文主要涉及Quasar在Actor模型的实现上建立的,该模型建立在Quasar光纤之上,但请记住,您可以在没有actor的情况下使用Quasar。
类星体演员实现了上面概述的完整的演员范式,其中一些适用于Java 7,Java 8, Clojure和Kotlin 。 Quasar当前不支持Scala。
由于Quasar光纤的工作原理与线程非常相似,因此可以轻松地集成现有库,因此可以在不更改代码或进行最少代码更改的情况下使用当前工具和库,同时充分利用轻量级线程的效率。 这样可以保留现有代码,并避免API锁定。 Comsat项目利用Quasar的集成框架,以最少的代码为光纤提供了几个流行的标准API的端口移植(它还引入了Web Actors ,这是一个基于actor的新的HTTP,WebSocket和SSE的基于Web的API)。
Quasar光纤是通过创建和安排连续任务来实现的,并且由于JVM还不支持本机连续,因此Quasar通过选择性字节码检测来实现它们:当前可以阻塞光纤的方法需要通过注释进行显式标记,以便Quasar可以插入继续悬挂和恢复挂钩。 但是,可以使用实验性的自动Clojure工具,并且自动工具也将扩展到其他JVM语言。 可以作为附加的构建步骤或在运行时执行检测(通过JVM代理或大多数常见Servlet容器的类加载器)。
阿卡
Akka是用Scala编写的actor框架,除了Scala之外,它还支持Java 7,Java 8(从2.3.10开始的实验)。 它提供基于异步,基于回调的Actor DSL,而不是基于Erlang的基于光纤的Actor系统。 Akka不提供轻量级线程,而是依靠JVM线程来调度参与者。 Akka不是一个库,而是一个提供全方位服务的框架,涵盖了从配置和部署到测试的所有内容。
无阻塞
Akka和Quasar actor之间的主要区别是Akka使用了异步的非阻塞API,而Quasar –例如Erlang,Go,Clojure的core.async –使用了阻塞API:在Akka中,actor 实现了receive
方法,即当actor收到消息时触发的回调,而在Quasar中,actor 调用 receive
方法,该方法一直阻塞,直到收到消息为止。 从理论上讲,异步和直接(或阻塞)样式是双重的和等效的,因为它们可以相互转换 ,但是在实践中,实现的细节对性能和可伸缩性以及选择哪种样式有很大影响。编程语言可以使一种方法比另一种方法容易。
选择基于回调的异步方法的原因是,阻塞普通的OS线程会带来大量开销(就像许多线程的存在一样),而使用非阻塞API可以避免这种情况。 但是,由于Quasar(与Erlang和Go一样)具有真正的轻量级线程,因此阻塞几乎没有开销。
在语言方面,虽然Scala为monad提供了语法支持,这使处理异步代码变得更加简单,但是在对monad没有良好语法支持的语言(例如Java)中,阻塞方法要简单得多。 阻塞代码的优点不仅在于更简单,更具可读性和可维护性的 Java代码,还在于更加熟悉和兼容的代码,可以集成其他标准Java API。
API比较
Quasar Java API支持Java 7和8。Clojure支持是Pulsar的一部分, Pulsar是Quasar周围的一个很薄的包装层,非常习惯,并且提供了与Erlang相似的actor API。 Kotlin支持是最新添加的功能。 Kotlin是一种非常有前途的针对JVM和JavaScript的静态类型混合编程语言,由领先的供应商JetBrains的开发工具设计和构建,使其高效且可集成。 尽管Kotlin使使用现有Java API的效果比Java本身更有效,更安全,更轻松,更愉快。
Quasar还提供了一个集成工具箱,该工具箱可以添加对其他JVM语言的支持。
Akka在设计时主要考虑了Scala,但一段时间以来它一直在提供附加的Java API。
以下是Quasar和Akka Java API之间的比较。 尽管还不够详尽,但它涵盖了关键的差异。 这是一个简短的摘要:
演员定义
Quasar (Kotlin和Java)参与者实现了doRun
方法(或Clojure中的函数),就像在Erlang中一样,该方法可以使用任意语言控制流构造,并且只要开发人员认为合适就可以阻塞操作。 通常它将至少使用receive
(正常或选择性)和send
:
class MyActor extends BasicActor<String, MyActorResult> {
private final Logger log = LoggerFactory.getLogger(MyActor.class);
@Suspendable
@Override
protected MyActorResult doRun() throws InterruptedException, SuspendExecution {
// ...Arbitrary code here...
final String msg = receive(m -> {
if ("test".equals(m)) return "testMsg";
else return null; // Defer
});
// ...Arbitrary code here...
return new MyActorResult();
}
}
由