Akka教程——3.Actor 模型如何满足现代分布式系统的需求

如前一主题所述,常见的编程实践无法恰当地满足要求苛刻的现代系统的需求。值得庆幸的是,我们不需要废弃我们所知道的一切。相反,actor模型以一种有原则的方式解决了这些缺点,允许系统以更符合我们的心智模型的方式运行。actor模型抽象允许您从通信的角度来考虑您的代码,这与大型组织中人们之间发生的交流没有什么不同。

actor的使用​​使我们能够:

  • 强制封装而不求助于锁。
  • 使用协作实体对信号做出反应、改变状态并相互发送信号的模型来驱动整个应用程序向前发展。
  • 不要担心与我们的世界观不匹配的执行机制。

使用消息传递避免锁定和阻塞

Actor 不是调用方法,而是相互发送消息。发送消息不会将执行线程从发送者转移到目的地。actor可以发送消息并继续而不会阻塞。因此,它可以在相同的时间内完成更多的工作。

对于对象,当方法返回时,它会释放对其执行线程的控制。在这方面,actor的行为很像对象,它们对消息做出反应,并在处理完当前消息后返回执行。这样一来,actor就真正实现了我们想象中对象的执行:

 

传递消息和调用方法的一个重要区别是消息没有返回值。通过发送消息,一个actor将工作委托给另一个actor。正如我们在调用堆栈的错觉中看到的那样,如果它期望返回值,则发送 actor 要么需要阻塞,要么需要在同一线程上执行其他 actor 的工作。相反,接收者在回复消息中传递结果。

我们需要在模型中进行的第二个关键更改是恢复封装。Actor 对消息做出反应,就像对象对调用它们的方法“做出反应”一样。不同之处在于,不是多个线程“突入”我们的 actor 并对内部状态和不变量造成严重破坏,actor 独立于消息的发送者执行,并且它们依次对传入的消息做出反应,一次一个。虽然每个参与者按顺序处理发送给它的消息,但不同的参与者彼此并发工作,因此参与者系统可以同时处理硬件支持的尽可能多的消息。

由于每个 actor 始终最多处理一条消息,因此可以在不同步的情况下保持 actor 的不变量。这会在不使用锁的情况下自动发生:

总而言之,当 actor 收到消息时会发生以下情况:

  1. actor将消息添加到队列的末尾。
  2. 如果actor没有被调度执行,它被标记为准备执行。
  3. 一个(隐藏的)调度器实体接受 actor 并开始执行它。
  4. Actor 从队列的前面挑选消息。
  5. Actor 修改内部状态,向其他 Actor 发送消息。
  6. actor不是调度者。

为了完成这个行为,actor有:

 

  • A mailbox (the queue where messages end up).
  • A behavior (the state of the actor, internal variables etc.).
  • Messages (pieces of data representing a signal, similar to method calls and their parameters).
  • An execution environment (the machinery that takes actors that have messages to react to and invokes their message handling code).
  • An address (more on this later).

 

  • 邮箱(消息结束的队列)。
  • 行为(参与者的状态、内部变量等)。
  • 消息(表示信号的数据片段,类似于方法调用及其参数)。
  • 一个执行环境(接收具有消息的参与者并调用其消息处理代码的机制)。
  • 地址(稍后详细介绍)

消息进入演员邮箱。actor 的行为描述了 actor 如何响应消息(比如发送更多消息和/或改变状态)。执行环境编排线程池以完全透明地驱动所有这些操作。

这是一个非常简单的模型,它解决了前面列举的问题:

  • 通过将执行与信号分离(方法调用传输执行,消息传递则不然)来保留封装。
  • 不需要锁。修改 actor 的内部状态只能通过消息来实现,一次处理一条消息,以消除试图保持不变量时的竞争。
  • 任何地方都没有使用锁,发件人也不会被阻止。数以百万计的参与者可以高效地安排在十几个线程上,从而充分发挥现代 CPU 的潜力。任务委派是参与者的自然操作模式。
  • Actor 的状态是本地的而不是共享的,更改和数据通过消息传播,这映射到现代内存层次结构的实际工作方式。在许多情况下,这意味着仅传输包含消息中数据的缓存行,同时将本地状态和数据缓存在原始核心中。相同的模型完全映射到远程通信,其中状态保存在机器的 RAM 中,更改/数据作为数据包在网络上传播。

Actor 优雅地处理错误情况

由于我们不再有相互发送消息的参与者之间的共享调用堆栈,我们需要以不同的方式处理错误情况。我们需要考虑两种错误:

  • 第一种情况是由于任务中的错误(通常是一些验证问题,例如不存在的用户 ID)导致目标参与者的委托任务失败。在这种情况下,目标参与者封装的服务完好无损,只是任务本身出错了。服务参与者应该用一条消息回复发送者,展示错误情况。这里没有什么特别的,错误是域的一部分,因此成为普通消息。
  • 第二种情况是服务本身遇到内部故障。Akka 强制将所有actor组织成树状层次结构,即创建另一个actor成为新actor的父级。这与操作系统将进程组织成树的方式非常相似。就像流程一样,当一个参与者失败时,它的父参与者可以决定如何对失败做出反应。此外,如果父 actor 停止,则其所有子 actor 也将递归停止。这项服务称为监督,它是 Akka 的核心。

主策略通常由父 actor 在启动子 actor 时定义。它可以决定在某些类型的故障时重启子 actor 或在其他类型的故障时完全停止它。孩子们永远不会默默地死去(进入无限循环的显着例外),而是他们要么失败并且监督策略可以对错误做出反应,要么他们被停止(在这种情况下通知相关方)。总是有一个负责管理 actor 的实体:它的父级。重启从外部是不可见的:协作参与者可以在目标参与者重启时继续发送消息。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值