Akka Java容错和Actor重启

11

我目前正在研究Akka(Java版本)中的容错性和监督策略。

请参阅http://doc.akka.io/docs/akka/2.3.2/java/fault-tolerance.htmlhttp://doc.akka.io/docs/akka/2.3.2/general/supervision.html#supervision

以下是一些问题:

1) 当我们知道要期望哪些异常时,是否应该在Actor中使用try/catch块?为什么或者为什么不?如果不使用,是否应该依赖于监督策略来有效地处理子Actor可能抛出的异常?

2) 默认情况下,如果父Actor中没有明确配置监督器,则似乎任何抛出异常的子Actor都将默认重启。 那么如果您的整个系统中没有任何Actor携带状态,我们是否真的应该执行重启操作?

3) 如果由system.actorOf(...)创建的顶级Actor抛出异常,该怎么办?如何在Actor系统外提供监督策略?

4) 假设有一个Actor A,它有一个子Actor B。现在假设Actor A要求Actor B完成一些工作。

代码可能如下所示:

Future<Object> future = Patterns.ask(child, message, timeout);
future.onComplete(new OnComplete<Object>() {

    @Override
    public void onComplete(Throwable failure, Object result) throws Throwable {
             ... handle here    
    }

现在...如果演员A出现异常,那会怎么样?默认情况下,它会由其监督者重新启动。问题是,onComplete的“闭包”是否仍然会在将来某个时刻执行,或者在重新启动后被有效地“抹掉”?

5)假设我有这样的层次结构:A->B->C。另外假设我覆盖了preRestart,以便我不停止我的子节点。在A的preStart中,他调用getContext()。actorOf(B),并且在B的preStart中,他调用getContext()。actorOf(C)。如果A出现异常,那么系统中是否会存在多个actor B和多个actor C?

谢谢!

1个回答

10

这将是一个相当长的回答,但让我尽可能地有条不紊地解决您的问题。
此外,我将依赖于官方的Akka文档,因为我认为Akka是最好的文档化项目之一,我不想重复发明轮子。 :)

  1. Akka中容错性的良好介绍/概述在 [1]中。我认为这篇文章“总结”了Akka文档的几页内容。具体回应这一点,我认为这取决于:你可以try/catch异常,当然可以,但错误内核模式表明你应该“向下推送actor层次结构”任何可能失败的事情(这是为了防止或尽可能限制演员内部状态的丢失)。言归正传,如果您有一个非常特定的Exception,并且您知道如何将其作为消息处理的一部分处理,那么我认为捕获它没有任何固有问题。实际上,我可以想到至少一个特定的情况,在这种情况下,您想要捕获异常并处理它们:如果您的actor正在响应Pattern.ask,则需要在Failure中包装异常,如果您想要通知调用者。([2])。

  2. [3]所述,缺省的行为确实是Restart,但仅在消息处理期间抛出Exception时才会发生。请注意,默认情况下,ActorInitializationExceptionActorKilledException终止子进程,并记住在preStart中抛出的任何Exception都将被包装在ActorInitializationException中。
    至于是否应该在没有演员状态时使用Restart作为默认值..."好吧,根据定义,演员是在并发环境中安全访问和操作状态的抽象:如果没有状态,您可能需要使用Future而不是演员。一般来说,Restart被认为是典型用例的安全合理的默认值。在您的特定情况下(这不是演员系统的典型用例),您可以覆盖默认的监督策略。
    从“用户”角度来看,顶级演员仅是顶层。正如[4]中所解释的那样,任何顶级演员都将作为Guardian演员的子代创建,并具有正常的默认监督策略。此外,您可以使用属性akka.actor.guardian-supervisor-strategy修改默认值。请记住,在设计系统时应考虑Akka的层次性特点([5]),因此不要过多地使用顶级actors ([6])。

  3. 无论onComplete的回调是否被调用取决于A何时失败。如果它在B完成并响应A的请求之后失败,则可能会执行。否则,它将不会执行。它会随着旧的A实例而“清除”。

  4. 这有点令人困惑,但我将假设以下情况:

    • 当你说“A抛出异常”时,你指的是在消息处理(onReceive)中
    • 您的actor中有一个字段将存储getContext().actorOf(C)返回的ref。

简短的答案是:是的。根据您描述的场景,将存在多个BC的实例。然而,新的A实例不会知道这一点。它将引用新的B和间接引用新的C。这是合理和预期的,因为您已经手动明确地禁用了处理actor层次结构中的故障的默认清理逻辑(通过更改postRestart):现在你有责任进行清理,并且你描述的preStart实现没有这样做。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接