首页 理论教育 Akka架构详解

Akka架构详解

时间:2023-06-20 理论教育 版权反馈
【摘要】:Akka处理并发的方法基于一个并发模型设计和架构的Actor模型。当一个Actor的邮箱收到其他Actor发送过来的消息后,Akka框架会结合Scala语言强大的模式匹配功能对消息进行处理。

Akka架构详解

1.Akka是什么

Akka是一个用Scala语言编写的库,可用于简化编写容错的、高可伸缩性的Actor模型应用。它分为开发库和运行环境,同时提供了Scala和JAVA的开发接口,可以用来构建高并发、分布式、可容错、事件驱动的基于JVM的应用。

Akka处理并发的方法基于一个并发模型设计和架构的Actor模型。在基于Actor的系统里,所有的事物都是Actor,Actor是封装了状态State和行为(Behavior)的对象,Actor之间共享信息和发起任务的机制是消息传递,它们仅仅通过交换消息(messages)实现相互通信,这些消息被放置到收件人的邮箱(Mailbox)中。当一个Actor的邮箱(也就是消息队列)收到其他Actor发送过来的消息后,Akka框架会结合Scala语言强大的模式匹配功能对消息进行处理。它先建立一个消息队列,每次收到消息后,就放入队列,而它每次也从队列中取出消息体来处理(如图5-5所示)。通常都使得这个过程是循环的,让Actor可以时刻处理发送来的消息。更深入一点说,Akka在多个Actor和系统底层之间建立了一个层次(Layer),这样一来,Actor只需要处理消息就可以了。创建和调度线程、接收和分发消息以及处理竞态条件和同步的所有复杂性,都委托给框架,框架的处理对应用来说是透明的。

978-7-111-52860-9-Chapter05-138.jpg

图5-5 Akka的生命周期图

Akka作为一个轻量级的消息驱动系统,有五大特性:

(1)易于构建并行和分布式应用(Simple Concurrency&Distribution):使用Actor,应用可以异步处理请求并用独占的方式执行非阻塞操作。

(2)可靠性(Resilient by Design):系统具备自愈能力,在本地/远程都有监护。

(3)高性能(High Performance):在单机中每秒可发送50000000个消息。内存占用小,1GB内存中可保存2500000个Actor对象。

(4)可伸缩性(Extensible):可以在分布式环境下进行Scale out(横向扩展),线性扩充计算能力。

(5)弹性,无中心(Elastic-Decentralized):自适应的负责均衡。

978-7-111-52860-9-Chapter05-139.jpg

图5-6 Akka的组织关系

2.Actor系统

在基于Actor的设计里,各个Actor以树形结构组织起来,像一个经济组织变成一个层级结构(如图5-6所示),也就是所谓的Actor系统。Actor系统的典型特点是任务拆分和委派,一个Actor可以在系统监督下完成特定的功能,比如将它的任务分解成更小,更易于管理。为达到目的,它启动一个它监督下的子Actor(child Actor)。这样做,不仅需要任务本身结构清晰,而且作为结果的Actor也必须经得起它们要处理的消息的仔细推敲,应该如何处理正常逻辑,又如何处理失败都需要仔细的推敲。如果一个Actor不具备处理某种特殊场景的能力,它会发送一个相应的故障信息给监管者来寻求帮助。递归结构,允许他们在合适层次上处理失败的消息。

在Akka里面,和Actor通信的唯一方式就是通过ActorRef。ActorRef代表Actor的一个引用,可以阻止其他对象直接访问或操作这个Actor的内部信息和状态。消息可以通过一个ActorRef以下面的语法协议中的一种发送到一个Actor:

“!”——发送消息并立即返回。

“?”——发送消息并返回一个Future对象,代表一个可能的应答。

每个Actor都有一个收件箱,用来接收发送过来的消息。收件箱有多种实现方式可以选择,默认的实现是先进先出(FIFO)队列。

Akka的Actor API中提供了每个Actor执行任务所需要的有用信息:

sender:当前处理消息的发送者的一个ActorRef引用。(www.xing528.com)

context:Actor运行上下文相关的信息和方法(例如,包括实例化一个新Actor的方法ActorOf)。

self:Actor本身的ActorRef引用。

3.Akka的容错和监管者策略

在Akka里面,一个监管者Actor对于从子孙Actor传递上来的异常的响应和处理方式称作监管者策略。在Actor系统里,每个Actor都是其子孙Actor的监管者。如果Actor处理消息时失败,它就会暂停自己及其子孙Actor并发送一个消息给它的监管者,通常是以异常的形式。

当一条消息指示有一个错误到达了一个监管者,它会采取如下行动之一:

(1)恢复子Actor(及其子孙Actor),保持内部状态。当子Actor的状态没有被错误破坏,还可以继续正常工作的时候,可以使用这种策略。

(2)重启子Actor(及其子孙Actor),清除内部状态。这种策略应用的场景和第一种正好相反。如果子Actor的状态已经被错误破坏,在它可以被用到Future之前有必要重置其内部状态。

(3)永久地停掉子Actor(及其子孙Actor)。这种策略可以用在下面的场景中:错误条件不能被修正,但是并不影响后面执行的操作,这些操作可以在失败的子Actor不存在的情况下完成。

(4)停掉自己并向上传播错误。适用场景:当监管者不知道如何处理错误,就把错误传递给自己的监管者。

而且,一个Actor可以决定是否把行动应用在失败的子孙Actor上抑或是应用到它的兄弟上。有两种预定义的策略:

1)OneForOneStrategy:只把指定行动应用到失败的子Actor上。

2)AllForOneStrategy:把指定行动应用到所有子孙Actor上。

4.本地透明性

Akka架构支持本地透明性,使得Actor完全不知道它们接受的消息是从哪里发出来的。消息的发送者可能驻留在同一个JVM,也有可能是存在于其他的JVM(或者运行在同一个结点,或者运行在不同的结点)。Akka处理这些情况对于Actor(也即对于开发者)来说是完全透明的。唯一需要说明的是跨越结点的消息必须要被序列化

最后,为了充分发挥Akka的能力,在设计和实现系统时,有些要点值得考虑:

(1)应尽最大可能为每个Actor都分配最小的任务。

(2)Actor应该异步处理消息,不应该阻塞,否则就会发生上下文切换,影响性能。具体来说,最好是在一个Future对象里执行阻塞操作(例如IO),这样就不会阻塞Actor。

(3)要确认你的消息都是不可变的,因为互相传递消息的Actor都在它们自己的线程里并发运行。可变的消息很有可能导致不可预期的行为。

(4)由于在结点之间发送的消息必须是可序列化的,所以必须要记住消息体越大,序列化、发送和反序列化所花费的时间就越多,这也会降低性能。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈