本章描述了如何在分布式的Actor系统中识别和定位Actor。
其中涉及到Actor系统分层监督的中心思想以及Actor之间经过多网络节点的消息通信。
上图显示了Actor系统中最重要的实体之间的关系
什么是 Actor Reference (Actor引用)
actor reference是ActorRef的的子类型,ActorRef的主要作用是支持向它
所代表的Actor发送消息。
每个actor都可以通过self来访问它的规范(本地)引用,默认情况下,
此引用也被作为给其他Actor发送消息的发件人使用。
在消息处理期间,Actor可以通过访问sender字段获取消息发送方的引用。
根据actor系统的配置,有几种不同类型的actor reference:
* 纯本地actor引用(Purely local actor references)被没有配置为支持联网功能的actor系统使用。
如果通过网络连接发送到远程JVM,这些actor引用将不起作用。
开启远程之后,本地actor引用(Local actor references)由同一JVM内支持联网的actor系统使用,
为了能发送到其他网络节点,这些actor引用需要包括协议和远程寻址信息。有一种本地actor引用的子类型是由routers(混合了Router特质的actor)使用。
其逻辑结构与上述的本地引用相同,但发送消息会直接发送给他们的子actor。远程Ator引用(Remote actor references)可以代表远程Actor,
发送消息给他们的时候消息会被序列化并发送到远程JVM。有一些特殊类型的Actor引用,表现上和local actor reference相似。
PromiseActorRef是Promise的特殊代表,目的是通过Actor的回应完成。
akka.pattern.ask创建这个actor引用。DeadLetterActorRef是dead letter服务的默认实现,
Akka将所有目的地被关闭或不存在的消息发送到该服务。EmptyLocalActorRef是Akka在查找不存在的本地actor路径时返回的内容:
它相当于一个DeadLetterActorRef,但它保留了这个路径,
以便Akka可以通过网络发送它并将它与该路径下其他已有的actor引用进行比较,
以发现存在的可能。
什么是Actor Path
由于Actor是以严格等级的方式创建的,所以存在一个由Actor姓名根据父子关系
顺序递归到root而形成的actor系统的的唯一序列。
这个序列类似与文件系统中的文件夹包含关系,
因此我们采用名称“path”来表示它。正如在一些真实的文件系统中,
Actor也有“符号链接”,即一个Actor可以使用多于一条路径到达,
即一个Actor可以通过不止一条路径来访问。
一个Actor路径由一个锚点组成,该锚点标识了Actor系统,
后面跟随者从root到指定Actor的路径元素的连接; 路径元素是遍历actor的名称,
并用斜杠分隔。
Actor Reference和Path的区别
一个Actor引用指定单独的Actor,它的生命周期和该Actor的生命周期一致;
一个Actor路径代表一个名字,这个名字可能会或不会被Actor占据,
并且路径本身是没有生命周期的,也永远不会失效。
您可以创建Actor路径而不创建Actor,但不能创建Actor引用而不创建相应的actor。
这些定义是不支持actorFor的,
这就是为什么弃用actorFor而选用actorSelection的原因之一
你可以创建一个Actor,终止它,然后用同样的actor path创建一个新的actor。
新创建的actor指定的是新的actor,和终止的不是一个。对于新的actor,
旧的actor引用是无效的,新的actor无法接收到发往旧的actor引用的消息,
即使他们有相同的路径。
Actor Path Anchors (锚)
每个actor路径都有一个地址组件,
描述相应actor可访问的协议和位置,后面跟随从层次结构root开始的actor名称,例如:
> "akka://my-sys/user/service-a/worker1" // purely local
> "akka.tcp://my-sys@host.example.com:5678/user/service-b" // remote
> "cluster://my-cluster/service-c" // clustered (Future Extension)
这里的akka.tcp是2.2版本默认的远程运输协议,可以插入别的协议,比如akka.udp
Actor的逻辑路径
由root到actor的唯一路径
Actor的物理路径
如果父Actor在不同的网络上,逻辑路径需要跨越网络而付出昂贵代价,
因此,每个Actor有一个物理路径。
如何获取Actor引用
对于如何获得Actor引用一般有两种方法:通过创建Actor或者通过查找Actor,
后者可以通过具体actor路径和actor逻辑层次来完成。
创建Actor
一个actor系统通常使用ActorSystem.actorOf方法在守护actor下
开始创建actor,然后用ActorContext.actorOf在已创建的actor下生成一个actor树。
这些方法会给新创建的actor返回一个引用。每一个actor可以直接访问
其父actor,自身和子actor(通过ActorContext)。
这些引用将用在给别的actor发送消息时能收到回复。
通过路径查找actor
另外,actor引用可以通过ActorSystem.actorSelection方法来查找。
注意:弃用actorFor而选用actorSelection的原因是,
利用前者来获取actor引用对于本地和远程的actor结果是不一样的。
绝对路径和相对路径
类似与linux路径,路径元素中包含两个点(”..”)可以用来访问父actor
相对路径 context.actorSelection("../brother") ! msg
绝对路径 context.actorSelection("/user/serviceA") ! msg
在逻辑层次结构中查询
既然actor系统是类文件系统层次结构,
通过一些linux路径通配符也是可行的:
比如可以用 “*” 来替换路径名称来表示选项,
它可以匹配0个或更多个actor。
context.actorSelection("../*") ! msg
比如这样会给当前actor自己和所有兄弟actor发消息。
总结actorOf VS actorSelection VS actorFor
* actorOf只能创建一个新的actor,当这个方法被调用的时候
(可能是任何的actor或actor system),
它会在当前context种创建一个直接子actor
* actorSelection只能在发送消息的时候查找已经存在的actor,
也就是说selection被创建时,既不能创建actor也不能验证actor的存在性。
* actorFor(已被actorSelection取代)只能查找一个已经存在的actor,
不能创建actor。
Actor Reference 和 Path Equality
当两个actor的引用有相同的路径并指向相同的actor化身的时候
它们就被认为是等价的。如果其中一个actor已经终止,则虽然路径相同则
不再等价。
注意:由于actor故障而重启的actor和之前是同一个,也就是说重启对于
ActorRef来说是透明的。
顶级actor路径的范围
在路径层次结构的根部有一个root监管者,
它用”/”来表示。下一个等级由如下列表所示组成:
- “/user”是所有用户创建最高等级的守护者actor;
通过ActorSystem.actorOf来创建。 - “/system”是所有系统创建最高等级的守护者actor,
例如日志监听器或者在actor系统启动时通过配置自动部署的actor。 - “/deadLetters”是死信actor,所有发送给已停止的或不存在的
actor的消息都被重新路由到此处
(消息也有可能在本地JVM中丢失)。 - “/temp”是所有短命的系统创建actor的守护者,
例如那些用于实现ActorRef.ask的actor。 - “/remote”,其下所有actor的人工路径,这些actor的监管者都是远程actor引用。