Akka的监管和监控

Akka的监管和监控

监管和监控

在 Actor 系统 中说过,监管描述的是actor之间的依赖关系:监管者将任务委托给下属,并相应地对下属的失败状况进行响应。当一个下属出现了失败(即抛出一个异常),它自己会将自己和自己所有的下属挂起,然后向自己的监管者发送一个提示失败的消息。基于所监管的工作的性质和失败的性质,监管者可以有4种基本选择:

  1. 恢复下属,保持下属当前积累的内部状态
  2. 重启下属,清除下属的内部状态
  3. 永久地停止下属
  4. 升级失败(沿监管树向上传递失败),由此失败自己

警告
监管相关的父-子沟通,使用了特殊的系统消息及其固有的邮箱,从而和用户消息隔离开来。这意味着,监管相关的事件相对于普通的消息没有确定的顺序关系。在一般情况下,用户不能影响正常消息和失败通知的顺序。

顶级监管者

enter image description here

一个actor系统在其创建过程中至少要启动三个actor,如上图所示。

  • /user: 守护Actor

这个名为”/user”的守护者,作为所有用户创建actor的父actor,可能是需要打交道最多的。使用system.actorOf()创建的actor都是其子actor。

  • /system: 系统守护者

这个特殊的守护者被引入,是为了实现正确的关闭顺序,即日志(logging)要保持可用直到所有普通actor终止,即使日志本身也是用actor实现的。

  • /: 根守护者

根守护者所谓“顶级”actor的祖父,它监督所有在Actor路径的顶级作用域中定义的特殊actor,使用发现任何Exception就终止子actor的SupervisorStrategy.stoppingStrategy策略。

重启

重启过程中所发生事件的精确次序是:

  1. actor被挂起(意味着它不会处理正常消息直到被恢复),并递归挂起其所有子actor
  2. 调用旧实例的 preRestart hook (缺省实现是向所有子actor发送终止请求并调用 postStop)
  3. 等待所有子actor终止(使用context.stop())直到 preRestart 最终结束;这里所有的actor操作都是非阻塞的,最后被杀掉的子actor的终止通知会影响下一步的执行
  4. 再次调用原来提供的工厂生成actor的新实例
  5. 调用新实例的postRestart方法(其默认实现是调用preStart方法)
  6. 对步骤3中没有被杀死的所有子actor发送重启请求;重启的actor会遵循相同的过程, 从步骤2开始
  7. 恢复这个actor

Actor引用, 路径与地址

什么是Actor引用?

Actor引用是 ActorRef 的子类,其最重要的目的是支持向它所代表的actor发送消息。每个actor通过self字段来访问自己的标准(本地)引用;在给其它actor发送的消息中也缺省包含这个引用。反过来,在消息处理过程中,actor可以通过sender()方法来访问到当前消息的发送者的引用。

什么是Actor路径?

由于actor是以一种严格的树形结构样式来创建的,所以沿着子actor到父actor的监管链,一直到actor系统的根存在一条唯一的actor名字序列。这个序列可以被看做是文件系统中的文件路径,所以我们称之为“路径”。就像在一些真正的文件系统中一样,也存在所谓的“符号链接”,即一个actor也许能通过不同的路径被访问到,除了原始路径外,其它的路径都涉及到对actor实际监管祖先链的某部分路径进行转换的方法。

如何获得Actor引用?

actor引用的获取方法分为两类:通过创建actor,或者通过查找actor。后一种功能又分两种:通过具体的actor路径来创建actor引用,和查询actor逻辑树。

创建Actor

一个actor系统通常是在根守护者上使用ActorSystem.actorOf创建actor来启动,然后在创建出的actor中使用ActorContext.actorOf来展开actor树。这些方法返回的是指向新创建的actor的引用。每个actor都拥有到它的父亲,它自己和它的子actor的引用(通过ActorContext访问)。这些引用可以与消息一起被发送给别的actor,以便接收方直接回复。

通过具体的路径来查找actor

另外,可以使用ActorSystem.actorSelection来查找actor引用。“选择”可在已有actor与被选择的actor进行通讯的时候用到,在投递每条消息的时候都会用到查找。

为了获得一个绑定到指定actor生命周期的ActorRef,你需要发送一个消息,如内置的Identify信息,向指定的actor,所获得的sender()即为所求。

val selection = context.actorSelection(“/user/serviceA”)
selection.tell(new Identify(identifyId), getSelf());

总结: actorOf vs. actorSelection vs. actorFor

Note

以上部分所描述的细节可以简要地总结和记忆成:

actorOf 永远都只会创建一个新的actor,这个新的actor是actorOf所调用上下文(可以是任意一个actor或actor系统本身)的直接子actor
actorSelection只会在消息送达后查找已经存在的actor集合,即不会创建actor,也不会在创建选择集合时验证actor是否存在。
actorFor(废弃,已经被actorSelection取代) 永远都只是查找到一个已存在的actor,不会创建新的actor。

Actor路径的顶级作用域

在路径树的根上是根监管者,所有其他actor都可以从通过它找到;它的名字是”/“。在第二个层次上是以下这些:

  • “/user” 是所有由用户创建的顶级actor的监管者;用 ActorSystem.actorOf创建的actor在其下。
  • “/system” 是所有由系统创建的顶级actor的监管者,如日志监听器,或由配置指定在actor系统启动时自动部署的actor。
  • “/deadLetters” 是死信actor,所有发往已经终止或不存在的actor的消息会被重定向到这里(以尽最大努力为基础:即使在本地JVM,消息也可能丢失)
  • “/temp”是所有系统创建的短时actor的监管者,例如那些在ActorRef.ask的实现中用到的actor。
  • “/remote” 是一个人造虚拟路径,用来存放所有其监管者是远程actor引用的actor。