Chinaunix首页 | 论坛 | 博客
  • 博客访问: 471189
  • 博文数量: 153
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1575
  • 用 户 组: 普通用户
  • 注册时间: 2016-12-20 17:02
文章分类

全部博文(153)

文章存档

2017年(111)

2016年(42)

我的朋友

分类: Java

2017-05-24 16:08:42

2.5 角色的引用、路径和地址

这一章描述,角色在一个有可能是分布式的角色系统中是如何被识别和定位的。它关系到了形成的内在监管层级以及角色跨越多个网络节点之间通信的位置透明化。

上述图片显示了角色系统中几个最重要实体之间的关系,请仔细阅读。


2.5.1什么是一个角色引用?

一个角色引用是ActorRef的一个子类型,它的主要目的是为它所代表的角色提供发送消息的功能。每个角色可以通过self字段访问自己指定(本地)的引用,这个引用包括发送者引用,默认会发送所有消息给别的角色。相反的,在消息处理期间,这个角色可以访问发送者引用,通过sender方法来呈现当前的消息。

这里提供了几个基于角色系统配置的不同类型的角色引用:

  1. 角色系统中的纯本地引用被配置成不支持网络功能的,这些角色引用发送的消息不能通过一个网络发送到另一个远程的JVM。
  2. 角色系统中的本地引用在被启用时,它代表了那些在同一个JVM里的角色支持网络功能。为了发送消息给别的网络节点,这些引用包含了协议和远程地址信息。
  3. 这里有一个用于路由器的本地角色引用的子类型(即角色混合了路由器的特性)。它的逻辑结构和上述的本地引用一样,有一点不同的是,向它们发送的消息会被分发给它们的子角色中的一个。
  4. 远程角色引用表示了哪个角色可以通过远程通信到达,即发送消息给它们会透明的序列化消息,并把它们发送给远程的JVM。
  5. 这里有几个角色引用的特殊类型,它们代表了角色引用的所有实用目的:
  • PromiseActorRef是Promise的一个特殊代表,它被用于完成一个角色的响应。akka.pattern.ask创建这个角色引用。
  • DeadLetterActorRef是死亡信件服务的默认实现,定义那些Akka路径中终点是关闭或不存在的消息。
  • EmptyLocalActorRef是Akka查找一个不存在的本地角色路径时返回的:它等同于DeadLetterRef,不过它保留了它的路径,这样Akka可以通过网络把它发送出去,然后可以通过它的路径和别的已经存在的角色引用进行比较,这样就能得到一些已经死亡的角色。
  1. 还有一些你可能还没见过的一次性的内部实现:
  • 有一个角色引用,它并不呈现为一个角色,它只作为一个伪管理员的根部守护者(guardian,下同),我们称它为“行走在时空泡沫中”。
  • 第一个日志服务开启之前,事实上激起角色创建的工具是一个伪造的角色引用,它能接收日志事件并把它们直接打印到标准输出中,它就是Logging.
  • StandardOutLogger。


2.5.2什么是一个角色路径?

既然角色们在严格的层级结构中创建,也就存在有一个角色名称的惟一序列,这些名称是递归地通过双亲与子女之间的监管关系命名的,一直到角色系统的根 。这个序列可以看成是文件系统中的文件夹,因此我们采用路径(path)这样的名字来关联它。在一些真实的文件系统中,它们也叫“符号链接”,即一个角色可以通过不止一条路径来访问,其中除了一个涉及到一些从角色的实际监管祖先行列中分离出来的转换。这些特性会在下面的小节中描述。

一条角色路径包含一个锚,它可以识别角色系统,后面紧跟着的是路径元素,从根守护者到指定的角色。路径元素遍历角色的名字,用斜杠隔开。


2.5.2.1 角色引用和角色路径之间有什么区别?

一个角色引用指定单个角色,并且它的生命周期和角色的生命周期一致;一条角色路径表示一个名字,它可能被一个角色占据,并且它没有生命周期,它不会变成无效状态。创建一条角色路径的同时可以不用创建角色,而角色引用则不一样,它必须创建与之关联的角色。

注意:这些定义是不支持actorFor的,这就是为什么弃用actorFor而选用actorSelection的原因之一。

你可以创建一个角色,终止它,然后用相同的角色路径创建一个新的角色。新创建的角色是另一个新的角色,和终止的角色不是同一个。旧角色的角色引用对于新的角色是无效的。发送给旧角色引用的消息不会交付给新的角色,尽管它们有相同的路径。


2.5.2.2 角色路径锚

每一个角色路径都有一个地址组件,描述协议和位置,这样使得关联的角色是可达的,接着是从层次结构根部起的角色名称。例如:

  1. “akka://my-sys/user/service-a/worker1″          // 纯本地
  2. “akka.tcp://my-sys@host.example.com:5678/user/service-b” //远程

这里的akka.tcp是2.2版本默认的远程运输协议,可以插入别的协议。一个远程主机如果使用UDP来访问,可以通过akka.udp。主机和端口部分取决于所使用的传输机制,但它必须遵循URI的结构规范。

2.5.2.3 角色的逻辑路径

通过父代监管者的链接指向的根守护者得到的唯一路径叫做角色的逻辑路径。这条路径完全匹配由祖先创建的角色,所以一旦角色系统的远程配置(和路径的地址组件)设置之后它就被完全确定。

2.5.2.4 角色的物理路径

当角色的逻辑路径描述一个角色系统内的功能位置的时候,基于配置的远程部署意味着一个角色可能创建于与它的父角色不同的网络主机上,即在不同的角色系统中。在这种情况下,从根守护者中获得角色需要遍历网络,这一操作要付出昂贵的代价。因此,每一个角色也有一个物理路径,开始于角色实际驻留的角色系统的根守护者。用这个路径作为发送者引用,当需要查询别的角色时,会让他们直接回复给这个角色,这样可以最小化由路由带来的延迟。

重要的一点就是,一个角色的物理路径不会跨越多个角色系统或虚拟机。这意味着如果角色的祖先其中有一个是远程监管,那么它的逻辑路径和物理路径会被分离开。


2.5.3如何获得角色引用?

有两种方法来获得角色的引用:通过创建角色或者查找,后者通过具体的角色路径和查询角色的逻辑层次来创建两种风格的角色。

2.5.3.1创建角色

一个角色系统通常通过使用ActorSystem.actorOf方法在守护者角色下开始创建角色,然后利用这个方法在已创建的角色下生成一个角色树。这些方法会返回一个引用给新创建的角色。每一个角色可以直接访问(通过它的ActorContext)到它的父角色,自己以及子角色的引用。这些引用会被包含在消息中发送给别的角色,使它们能够直接回复。

2.5.3.2通过具体路径查找角色

另外,角色引用可以通过ActorSystem.actorSelection这个方法来查找。被选择的角色可以与上述角色(审校者注:原文为the selection can be used for communicating with said actor,而本文到此为止仅提到过几种角色类型和创建角色的方式,尚未提及具体角色,本人认为所谓said actor应是前面提到的几种类型角色)通讯,而投递消息时被选择的相关角色会被查找。

为获得一个被绑定到某个特定角色生命周期的ActorRef,你需要发送一个消息(例如内置Identify的消息)给这个角色并使用角色通过sender()回复的引用。

注意:弃用actorFor而选用actorSelection的原因是,利用它来获取角色引用对于本地和远程的角色表现是不一样的。例如一个本地角色引用,被指定的Actor需要在查询之前存在,否则获得的引用将会是一个EmptyLocalActorRef,即使一个拥有确切路径的角色在获得角色引用之后被创建。通过actorFor获得的远程角色引用的行为不同,而且将消息发送给这样一个引用,会为了每一条消息的发送在远程系统中通过路径查找角色。

绝对路径 VS 相对路径

ActorSystem.actorSelection或ActorContext.actorSelection,可在任何角色内部通过context.actorSelection得到该对象的引用。在ActorSystem中,一个角色选择就像产生了一个它的双胞胎兄弟,而不是从启动它的角色所在角色树的根查找。路径元素中包含两个点(”..”)可以用来访问父角色。你可以像下面的例子一样向它的兄弟发送一条消息:

1 context.actorSelection(“../brother”) ! msg

通常情况下也可以通过绝对路径在上下文中进行查找:

1 context.actorSelection(“/user/serviceA”) ! msg

它们都能正常的工作。

2.5.3.3 在角色逻辑层次结构中查询

既然角色系统创建一个类文件系统层次结构,通过某些方式由Unix shell支持的路径匹配方式也是有可行的:你可以用通配符(“*”和“?”)来替换路径名称来表示选项,它可以匹配0个或更多的角色。因为结果不是单个的角色引用,它有一个不同的ActorSelection类型,并且不支持ActorRef的全套操作。选择集可以通过ActorSystem.actorSelection和ActorContext.actorSelection来制定,并支持发送消息:

1 context.actorSelection(“../*”) ! msg

上述代码会给当前角色和所有的兄弟角色发送msg。至于通过actorFor来获得引用,为了执行消息发送的功能,需要完成监管层级结构的遍历。角色集合的具体匹配可能会改变,即使一个消息已经在发送给接收者的途中,监控一个选择集的现场变化是不可能的。为了解决发送请求与收集所有应答的不确定性,需要提取出发送者引用,然后监控发现的所有具体角色。这个问题将会在未来的版本中得到改善。

概括:actorOf VS actorSelection VS actorFor

注意:上述章节内容可以概括如下,这样有助于记忆:

  1. actorOf只能创建一个新的角色,当这个方法被调用的时候(可能是任何的角色或角色系统),它会创建一个上下文的直接子角色。
  2. actorSelection只能在投递消息的时候查找已经存在的角色,也就是说选择集被创建时,既不能创建角色也不能验证当角色的存在性。
  3. actorFor(已被actorSelection取代)只能查找一个已经存在的角色,不能创建角色。


2.5.4 角色引用和路径等价

ActorRef的等价性体现了如下意图,即ActorRef与目标角色的化身(审校者注:原文为incarnation,意思应该是角色的实际功能、内容、引用等意思,下同)相一致。当两个角色的引用有相同的路径并指向相同的角色化身的时候就被认为是等价的。一个引用指向一个终止的角色不等价于指向另一个有相同路径的角色(重建)。注意,由于故障而重启的角色跟之前的是同一个,即重启对于ActorRef的用户来说是不可见的。

通过actorFor获得的远程角色引用不包括底层角色的完整信息,因此这些引用不等价于通过actorOf,sender或context.self获得的引用。因此actorFor被弃用,而被actorSelection代替。

如果你需要在一个集合中跟踪角色引用,并且不关心角色的真正化身,你可以用ActorPath作为键,因为在比较角色路径的时候,目标角色的标识不是要考虑的因素。


2.5.5 重复使用角色路径

当一个角色终止,它的引用会指向一个死信邮箱,DeathWatch会发布它最终的转换,通常不再希望起死回生(因为角色的生命周期不允许这样)。但它后面可能会创建一个路径完全相同的角色——只是由于在没有保留已经有效创建的所有角色的情况下无法执行相反的操作——这不是好的实践:通过actorFor获得的远程角色,在死亡后,又突然又开始工作,然而在这个转换和其它任何事件之间的顺序没有任何担保,因此该路径的新角色可能会接收到发送给以前角色的信息。

这可能是在非常特殊情况下的正确的事情,如果恰恰是角色监管人的话,就要去限制处理,因为它是唯一一个可以可靠检测正确注消命名的角色,一旦它出问题,之前新创建的子角色都会失败。

当被检测者不得不在特定路径上实例化的时候,在测试期间也可能要求这样(审校者注:此处应指重复使用角色路径)在这种情况下,最好去模拟它的监管人,这样它就可以在测试过程中把终止信息投递给合适的节点,使得后者能够等待名字正确的取消。


2.5.6 远程部署的相互影响

当一个角色创建子角色,角色系统的发布者会决定是否把新的角色放在同一个JVM或另一个节点上。第二点,角色的创建会在不同的JVM之间触发一个网络连接,从而包含在不同的角色系统中。远程系统会把新的角色放置在一个指定的路径下,新角色的监管者会是一个远程角色引用(表示创建它的角色)。在这个情况下,context.parent(监管者引用)和context.path.parent(这个角色路径中的父节点)不是同一个角色。然而,在监管者内部查找子角色的名字,会在远程节点上找到它,本地仅保持逻辑结构,例如给未定(审校者注:原文为resolved actor)角色引用发送消息。

2.5.7 地址部分用来干什么?

当在网络中发送一个角色引用,它通过路径来表示。因此,该路径必须充分编码,把底层角色需要的所有信息发送给它。这一点通过如下方式实现:通过把编码协议、主机和端口作为路径字符串的地址部分。当角色系统从一个远程节点接收到一个角色路径,它会检查该路径地址是否匹配本角色系统,如果匹配本角色系统,它被解析为本地角色引用。否则,它就是一个远程角色引用的表示。


2.5.8 角色路径的顶级作用域

在路径层次结构的底部有一个根部守护者,在它上面可以找到所有其它的角色;它用”/”来表示。下一个等级由如下列表所示组成:

  1. “/user”是所有用户创建最高等级角色的守护者角色;通过ActorSystem.actorOf来创建。
  2. “/system”是所有系统创建最高等级角色的守护者角色,例如日志监听器或者在角色系统启动时通过配置自动部署的角色。
  3. “/deadLetters”是死信角色,所有发送给已停止的或不存在的角色的消息都被重新路由到此处(以尽力而为原则,消息也有可能在本地JVM中丢失)。
  4. “/temp”是所有短命的系统创建角色的守护者,例如那些用于实现ActorRef.ask的角色。
  5. “/remote”,其下所有角色的人工路径,这些角色的监管者都是远程角色引用。


为角色构建名称空间的需要,是源于一个非常简单的中心设计目标:在层次结构中万物皆角色,以及所有的角色以相同的方式运作。因此你不仅仅可以查找你创建的角色,你还可以查找系统守护者并给它发送消息(在这种情况下它会踏实的丢弃)。这个强大的原则,意味着没有奇怪的东西需要去记住,它使整个系统更加的统一和一致。

如果你想要了解更多关于角色系统最高等级结构的知识,请查看顶级监管者


阅读(2021) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~