Actor 系统
Actor 是封装状态和行为的对象,它们通过交换放在收件人邮箱中的消息进行专门的通信。从某种意义上说,Actor 是面向对象编程最严格的形式,但最好将其视为“人”:当与 Actor 一起建模解决方案时,设想一组人员并为其分配子任务,将其功能安排到组织结构中,并考虑如何升级失败(所有这些都得益于非实际地与人打交道,这意味着我们不需要关心他们的情感状态或道德问题)。结果可以作为构建软件实现的一个心理脚手架(mental scaffolding
)。
- 注释:
ActorSystem
是一个重量级架构,它将分配1 … N
个线程,因此为每个逻辑应用程序都创建一个线程。
层次结构
就像在经济组织中一样,Actor 自然形成等级制度。一个负责监督程序中某个函数的 Actor 可能希望将其任务拆分为更小、更易于管理的部分。为此,它启动了由它监督的子 Actor。在「这里」解释监督细节的同时,我们将集中讨论本节中的基本概念。唯一的先决条件是要知道每个 Actor 只有一个监督者,这就是创建它的 Actor。
Actor 系统的典型特征是,任务被拆分和委托,直到它们变得足够小,可以一块处理。这样做,不仅任务本身结构清晰,而且结果 Actor 可以根据他们应该处理哪些消息、应该如何正常反应以及应该如何处理失败来进行推理。如果一个 Actor 没有处理特定情况的方法,它会向其监督 Actor 发送相应的失败消息,请求帮助。然后,递归结构允许在正确的级别处理故障。
将其与易于转入防御编程(defensive programming
)的分层软件设计进行比较,目的是不泄漏任何故障:如果问题传达给了正确的人,那么可以找到比试图将所有事情“隐藏”在“地毯下”更好的解决方案。
现在,设计这样一个系统的困难在于如何决定谁应该监督什么。没有单一的最佳解决方案,但有一些指导方针可能会有所帮助:
- 如果一个 Actor 管理另一个 Actor 正在做的工作,例如通过传递子任务,那么管理 Actor 应该监督子 Actor。原因是管理 Actor 知道预期的故障类型以及如何处理。
- 如果一个 Actor 携带非常重要的数据(即,如果可以避免,其状态不会丢失),则该 Actor 应向其监督的子 Actor 找出任何可能危险的子任务,并处理这些子 Actor 的故障。根据请求的性质,最好为每个请求创建一个新的子级,这样可以简化收集答复的状态管理。这就是 Erlang 的“错误内核模式”。
- 如果一个 Actor 依靠另一个 Actor 来履行职责,它应该观察另一个 Actor 的活动,并在接到终止通知后采取行动。这与监督不同,因为监督方对监督策略没有影响,应该注意的是,单独的功能依赖性并不是决定将某个子 Actor 放在层级中何处的标准。
这些规则总是有例外的,但是不管你是遵守规则还是违反规则,你都应该有一个理由。
配置容器
Actor 系统作为 Actor 的协作集合,是管理共享设施(如调度服务、配置、日志记录等)的自然单元。具有不同配置的多个 Actor 系统可以在同一个 JVM 中共存,没有问题,Akka 本身没有全局共享状态。将其与一个节点内或通过网络连接的 Actor 系统之间的透明通信结合起来,可以看到 Actor 系统本身可以用作功能层次结构中的构建块。
Actor 最佳实践
- Actor 应该像好的同事一样:高效地工作,而不是不必要地打扰其他人,并且避免占用资源。翻译成编程语言,这意味着以事件驱动的方式处理事件并生成响应(或更多请求)。Actor 不应在可能是锁、网络套接字等外部实体上阻塞,即占用线程时被动等待,除非这是不可避免的;对于后一种情况,请参见下文。
- 不要在 Actor 之间传递可变对象。为了确保这一点,最好选择不可变的消息。如果通过将它们的可变状态暴露到外部来破坏 Actor 的封装,则会返回正常的 Java 并发域,并存在所有的缺点。
- Actor 被设计成行为和状态的容器,接受这一点意味着不经常在消息中发送行为(使用 Scala 闭包可能很诱人)。其中一个风险是不小心在 Actor 之间共享可变状态,而这种对 Actor 模型的违反不幸地破坏了所有属性。
- 顶级 Actor 是错误内核的最核心部分,因此要谨慎地创建它们,并且更倾向于真正的分层系统。这对于故障处理(同时考虑配置的粒度和性能)有好处,而且它还减少了对守护者 Actor 的压力,如果使用过度,这是一个单一的竞争点。
你不应该关心的事
Actor 系统管理配置使用的资源,以便运行其包含的 Actor。在一个这样的系统中,可能有数百万的 Actor,毕竟所有的赞歌(mantra
)都是将他们视为丰富的,并且他们在每个实例的开销只有大约 300 字节。当然,在大型系统中处理消息的确切顺序不受应用程序作者的控制,但这也是无意的。
终止 ActorSystem
当你知道应用程序的所有操作都已完成时,可以调ActorSystem
的terminate
方法。这将停止守护者 Actor,而守护者 Actor 又将递归地停止其所有子 Actor,即系统守护者。
如果要在终止ActorSystem
时执行某些操作,请查看「协调关闭」。
英文原文链接:Actor Systems.