Akka学习笔记(二):Actor Systems


Akka学习笔记(二):Actor Systems

Akka学习笔记(二):Actor Systems_第1张图片
图中表示的是一个Actor System,它显示了在这个Actor System中最重要实体之间的关系。

什么是actor,是一个封装了状态和行为的对象,每个actor都通过message交流,从自己的mailbox中读取别的actor发送的消息。

注意
ActorSystem是重量级的对象,会创建1...N个线程,所以一个application一个ActorSystem。

层次结构

假设有一个actor,它的一个功能过于复杂,为了降低复杂度,可以将这个功能划分成多个更小粒度的,更易管理的子任务,启动新的child actors,监控它们任务运行(关于监控,详见here)。每一个actor的创建者,也是其监控者。

设计一个actor system,我们要正确规划,哪一个actor负责监控,监控什么。几点建议如下:

  • 负责分发工作的actor,管理接受任务的actor,因为包工头知道所有任务出错了该怎么解决 :)
  • 拥有重要数据的actor,找出所有可能丢失该数据的子actor,监控,并处理它们的错误。类似Erlang的Error Kernel Pattern。(这段看不太明白)
  • 如果一个actor需要其他的actor传递其需求或职责,必将监控之。它应该查看其他actor的存活状态,已经是否完成完成任务,当然这不是监控范畴了,不涉及到监控策略

以上仅做参考 -..-,总有例外

Actor Path

可以认为Actor Path是通过字符串对Actor层级关系进行组合用以标识唯一Actor的一种方式。我们在创建Actor Path时,不用创建Actor;但如果没有创建对应的Actor,则不能创建Actor Reference。还可以创建一个Actor,再终止它,然后再以相同的Actor Path再创建一个新的Actor。新创建的Actor是Actor的新化身(Incarnation),但与旧的Actor并不是同一个。对于这个新化身而言,持有旧Actor的Actor Reference并不是有效的。消息发送给旧的Actor Reference,但不会被传递给新化身,即使它们具有相同的路径。

Actor Path包含协议、位置和actor的层级。如下是一些Actor Path的实例:

//purely local
"akka://my-sys/user/service-a/worker1"                   

// remote"akka.tcp://my-sys@host.example.com:5678/user/service-b" 

//clustered (Future Extension)"cluster://my-cluster/service-c"

有两种方式可以获得Actor Reference:创建Actor或查找。

要创建Actor,可以调用ActorSystem.actorOf(),它创建的Actor在guardian actor之下;接着可以调用ActorContext.actorOf()在刚才创建的Actor内生成Actor树。这些方法会返回新创建的Actor的引用。每个Actor都可以直接访问Actor Context来或得它自身、Parent以及所有Children的引用。

要查找Actor Reference,则可调用ActorSystem.actorSelection()方法。要获得限定到特定Actor的生命周期中的ActorRef,可以使用sender引用来发送一条消息如内建的Identity消息给Actor。

在查找ActorRef时,可以使用绝对路径或相对路径。如果是相对路径,可以用两个点(..)表示parent actor。例如:

context.actorSelection("../brother") ! msg

使用绝对路径的例子:

context.actorSelection("/user/ServiceA") ! msg

还可以使用通配符查询逻辑的Actor层级,例如下面的例子就是发送消息给除当前Actor之外的所有同级Actor(因为..代表parent,所以这里就意味找当前Actor的parent的下级Actor):

context.actorSelection("../*") ! msg

区别:actorOf vs. actorSelection vs. actorFor

  • actorOf:创建一个新的Actor。创建的Actor为调用该方法时所属的Context下的直接子Actor;
  • actorSelection:当消息传递来时,只查找现有的Actor,而不会创建新的Actor;在创建了selection时,也不会验证目标Actors是否存在;
  • actorFor(已经被actorSelection所deprecated):只会查找现有的Actor,而不会创建新的Actor。

远程部署的相互影响

当一个Actor创建一个Child时,Actor的系统部署器会决定这个新的Actor究竟属于同一个JVM,还是另一个节点。如果是后一种情况,Actor的创建就会通过在不同JVM的网络连接而触发,这属于不同的Actor系统。远程系统会将新的Actor放在一个特定的路径下,且新Actor的Supervisor应该是一个远程的Actor引用。而且,context.parent(Supervisor的引用)与context.path.parent(actor path的父节点)表示的不是同一个Actor。如下图所示:
Akka学习笔记(二):Actor Systems_第2张图片

注意图中展现的两个不同的Actor系统之间的Route关系。在左边的Actor系统中,Child Actor属于Remote ActorRef,它指向了右边远端Actor系统中的一个Actor节点,该Actor对于右边的Actor系统而言,属于Local ActorRef,但它的Parent Actor却是一个Remote ActorRef,它指向了左边对应的Local ActorRef。

Actor Path的Top-Level Scopes

Actor路径的根为”/”,而后续层级包括:”/user”, “/system”, “deadLetters”, “/temp”, “/remote”。

这里体现了Akka遵循“简单”原则的设计目标:层级中的任何事物都是Actor,且所有Actor的功能都采用同样的方式。

Actor最佳实践

  1. actors尽量不要阻塞
  2. actors间不要传递可变对象
  3. actor的state,behavior作为可变对象,是不能在actors中传递
  4. Top-level actors尽量少创建(没看懂 T T)

阻塞需要谨慎管理

很多种情况,需要重新细看,分析

我们不需要关心什么

actor会自动管理我们分配的固定资源。一个actor system可能有上百万个actors,毕竟actor是非常轻量级的,每个实例只占300字节。


你可能感兴趣的:(scala,akka)