分布式多媒体计算机系统
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.7 远程过程调用(RPC)

许多分布式系统基于进程间的显式消息交换,然而消息的发送和接收过程无法隐藏通信的存在,而通信的隐藏对于在分布式系统中实现访问透明性是极为重要的。使用消息传递来描述通信过程,比使用基于共享存储器的原语来描述要更困难。现代分布式系统常常含有数千个进程,这些进程分散在Internet等不可靠的网络中。除非用其他技术来代替这种原始的通信功能,否则要开发大规模分布式应用是极为困难的。这个问题由来已久,但是人们在很长一段时间内都没有找到合适的解决办法,直到Birrell和Nelson(1984年)在一篇论文中引入了一套与传统方法截然不同的通信处理手段——远程过程调用。虽然其中蕴含的思想很简单,但其中的含义非常复杂微妙。远程过程调用作为一种广泛使用的技术,已成为许多分布式系统的基础。

最早提出远程过程调用的是美国的Birrell和Nelson。其后,远程过程调用在Xerox工作站上实现,它非常类似于在单机编程过程中经常使用的过程调用(Procedure Call)。在分布式系统中,一个进程请求消息对远程计算机的进程发出调用,然后在远程服务器上执行这个过程,在这个过程完成以后,返回一个结果消息,再发送到请求这个调用的进程。这就是目前在分布式系统中广泛应用的一种进程通信的机制,称为远程过程调用(Remote Procedure Call,RPC),如图2-28所示。

图2-28 远程过程调用

2.7.1 远程过程调用的特点

远程过程调用是允许在分布式环境下的程序设计可以调用远程另一台机器上的进程而提供服务的过程,最主要的特点是,程序不需要知道调用的过程是本地还是远程。远程过程调用和传统的过程调用的不同是,调用者(Caller或Client)和被调用的进程(Server)是在不同的机器上的不同的进程。因此,远程过程调用更容易出故障。

(1)虽然基于消息传递和远程过程调用是很类似的,但是,两者的不同是两个通信进程的关系。在消息传递中,两个进程的关系是伙伴关系;而在远程过程调用中,两个进程的关系是主从关系。

(2)另外的不同是,在消息传递过程中,所有要求传递的值在传送之前都要明确地赋到消息域中。远程过程调用所传送参数的组装,即将这些参数列表汇集在一起组成消息的工作是靠系统完成的。

远程过程调用发送一个调用(客户进程)或请求到远地进程(被调用者)。被调用者或服务器进程执行这个过程和发回一个结果(响应)消息。这种消息交换示意图如图2-29所示。远程过程调用提供了双向信息流。

图2-29 消息交换示意图

远程过程调用的语义类似本地过程调用:

(1)调用者等待结果时被挂起。

(2)调用者能传递参数到远地过程。

(3)被调用的过程执行完后给调用者返回结果。

但是,由于调用者和被调用者是在异地不同机器上运行,这个过程不能存取调用者环境的数据和参数。

2.7.2 RPC的工作原理

远程过程调用(RPC)的机制最早是由美国的Birrell和Nelson提出的,在Xerox的工作站上实现了其基本的工作过程和原理。远程过程调用执行过程如图2-30所示。

图2-30 远程过程调用执行过程

(1)在调用过程中,调用环境挂起。参数的传递是跨过网络到这个被调用的环境,过程的执行在被调用的节点执行,执行完以后把结果再送回到调用者。

(2)在实现中引入了Stub结构,这种结构的最大特点是,它不要求对调用的程序和语言做任何改变。尽管远程过程调用和过程调用有不同的语义,但它们很类似。

图2-30给出了在远程过程调用中的下列5个部件,以及它们之间的相互关系。

(1)客户机。

(2)客户机存根。

(3)RPC通信包(也称为RPC执行程序)。

(4)服务器存根。

(5)服务器。

远程过程调用的具体操作步骤如下:

(1)当客户机(用户程序)要求调用一个远地的过程时,首先发出一个通常的本地调用给客户机存根(Client Stub),这个Stub过程被链接到客户机进程的地址空间。

(2)Client Stub响应执行两个任务:

① 将目标过程按照规范把过程和变量打包成一个或多个消息。

② 请求RPC程序(在传送层)传送到被调用者,同时调用进程挂起等待结果数据包送回。

(3)运行RPC调用程序,通过网络调用计算机将消息送到被调用的计算机中。

(4)被调用计算机运行RPC执行程序:

① 接收发来的消息。

② 给服务器Stub传送消息。

(5)服务器Stub执行两项任务:

① 拆包接收的消息。

② 在服务器Stub上执行一个本地调用过程,用标准的方法把参数、变量传送到服务器。

(6)当这个调用在服务器上执行完成后,再执行一返回结果从服务器到服务器的Stub。用本地调用返回到挂起的服务器Stub。

(7)服务器存根(Server Stub)接到结果后执行两项任务:

① 把结果按照规范进行打包,装配成一个或多个消息。

② 请求RPC调用程序,把它的结果消息送回到调用者的RPC中。

(8)服务器端口RPC调用程序把装配好的结果消息送回到调用计算机。

(9)在调用计算机上,RPC调用程序执行完成两项任务:

① 接收这些结果消息。

② 给客户机存根(Client Stub)传送结果消息。

(10)客户机存根执行返回结果的任务:

① 对发回的结果进行拆包,还原成结果。

② 把结果返回给调用者和用户,使最后调用者得到需要的结果值。

整个上述过程执行完毕后,另外的一个进程可以再次要求远程过程调用。只有客户机的Stub知道这个过程是远程的。RPC调用程序负责重传、回答和保护。RPC调用程序可以基于消息传递的通信来开发。远程过程调用是可靠的、封锁的、结构化的Send、Get-Request和Send-Response原语的发展。它有如下优点:

(1)它有很简洁、清晰的语义,使分布式系统很容易构造和实现。

(2)它是一种有效的在异地两个进程之间进行通信的形式。过程调用是非常简单快速通信的手段。

(3)它是一种通用的两个进程之间通信的方法和机制,在分布式系统中得到广泛的应用。

2.7.3 扩展的RPC模型

事实上,远程过程调用已经成为分布式系统中的通信标准。该模型之所以得以流行,应该归功于它的显著简明性。在本节中,将对原始RPC模型的两种扩展形式进行简要的讨论,设计这两种扩展形式的目的是克服RPC的某些缺点。

1.门(Door)

原始RPC模型假定调用者和被调用者之间通信的惟一手段是通过网络传递消息,一般来说,这个假定是正确的。然而,如果客户机和服务器驻留在同一台机器上,通常希望使用本地的进程间通信(IPC)功能,该功能由底层操作系统向运行在同一台机器上的进程提供。例如,在UNIX下,这种功能包括共享内存、管道以及消息队列。

本地IPC功能与基于网络的类似功能相比要高效得多,即使在后者用于同一台机器上的进程间通信的情况下也是如此。因此,如果性能方面的要求较高,就需要根据要处理的进程是否位于同一台机器上的具体情况,结合使用多种进程间通信机制。

作为一种折中的方法,一些操作系统提供一个与RPC等价的机制,供位于同一台机器上的进程使用,这种机制称为门。门是一类过程的总称,这种过程位于某个服务器进程的地址空间内,可由与该服务器进程位于同一台机器上的其他进程调用。门原先是为Spring操作系统设计的,Bershad等人于1990年开发了另一种称为Lightweight RPC的类似机制。

要对门进行调用,必须由本地操作系统提供支持,如图2-31所示。具体来说,首先,服务器进程必须对门进行注册,随后其他进程才能调用这个门。在注册一个门的时候,系统返回该门的标志符,该标志符可在以后用来为门赋予一个符号名称。注册是通过调用door_create完成的。如果要让其他进程调用注册过的门,只需给该门取个名字,并将该名字与该门在注册时得到的标志符关联起来即可。例如,在Solaris中,每个门都拥有一个文件名,文件名是通过调用fattach而与该门的标志符关联起来的。客户机利用系统调用door_call来请求对门进行调用,并在door_call中给出要调用的门的标志符以及其他必需的参数。操作系统随后向上调用注册该门的服务器进程。对服务器进程的向上调用导致服务器调用门。调用门所得到的结果通过系统调用door_return返回客户机进程。

图2-31 门(一种RPC机制)的使用原理

门的主要优点是,它允许在分布式系统的通信中使用一种单一的机制,即过程调用。

不幸的是,在这种情况下,应用程序开发人员必须了解哪些调用是在当前进程内部完成的,哪些调用是对本地机器上的不同进程发出的,而又有哪些调用是向远程进程发出的。

2.异步RPC

与在常规过程调用中的情形一样,当客户机调用远程过程时,客户机将会阻塞,直到有应答返回为止。在没有结果要返回的情况下,这种严格的请求—应答方式是不必要的,它只会导致客户机过程向远程过程发出调用请求之后处于阻塞状态,从而无法进行本来能够进行的其他有用的工作。不需要等待应答的例子有:从某个账户向另一个账户进行转账操作、向数据库添加条目、启动远程服务以及执行批处理操作,等等。

针对以上这些状况,RPC系统可以提供称为异步RPC(Asynchronous RPC)的功能。利用该功能,客户机可以在发出RPC请求后立即继续执行。在异步RPC中,服务器在接收到RPC请求后立即向客户机送回应答,之后再调用客户机请求的过程。应答的作用是向客户机确认服务器已准备开始处理该RPC请求。客户机接收到服务器的确认消息之后,将不会阻塞,而是继续向下执行。图2-32(a)中显示了异步RPC交互过程。作为对比,图2-32(b)显示了常规RPC交互过程。

图2-32 RPC中客户机与服务器的交互过程

如果在应答返回时,客户机还未做好接收的准备,从而没有做出任何动作,在这种情况下异步RPC也很有用。例如,客户机可能想预取一组主机的网络地址,以便随后与它们进行联络。当命名服务器正在搜集这些地址的时候,客户机可能想做其他事情。在这种情况下,通过两个异步RPC来进行客户机与服务器间的通信是很有意义的,如图2-33所示。客户机首先对服务器进行调用,把要查询的主机名清单交给服务器,并且客户机在接收到服务器关于已收到主机名清单的确认之后继续执行其他的程序。第二步调用是由服务器发出的,它对客户机进行调用,将查询到的地址清单交给客户机。两个异步RPC结合起来也称为延迟的同步RPC(Deferred Synchronous RPC)。

图2-33 客户机和服务器通过两个异步RPC进行交互

需要指出的是,还存在一些异步RPC的变异形式。在这些异步RPC中,客户机向服务器发送请求之后立即继续执行其他的程序。也就是说,客户机不等待服务器返回接受请求的确认。这种RPC称为单向RPC(One-Way RPC)。它的问题是,如果无法确保可靠性,客户机就无法确定它发出的请求是否将得到处理。

2.7.4 客户机/服务器的联编

1.概念

在分布式系统中,客户机和服务器有两种不同的协作方式。第一种情况是,假定客户机请求一个暂时的服务(Temporary Service);另一种情况是,客户机想生成一系列调用直接指向一个专门的服务过程。这意味着需要一个运行机制,以便在客户机和服务器之间建立长期的联编(Binding,也称为绑定)。

所谓的联编在不同的应用范围有具体的含义,例如在语言中指如何将数据名转换为机器地址的过程;而在数据库中是指把数据的一种视图转换成另一种视图。在分布式系统中,联编主要完成两个任务:

(1)确定服务器主机的网络地址。

(2)在该主机上确定合适的服务器进程。通过联编可以建立起客户机和服务器的关系。

确定为客户机提供所需服务的主机的网络地址的方法有下列两种。

① 由某节点维护一个数据库,记录其他节点所提供的服务。客户机进程首先和这个节点接触,以获得有关主机的地址。这种方法的最大缺点是,万一这个节点瘫痪,整个系统就无法使用。另外,当多个客户机同时访问这个节点上的服务器地址列表时,该节点显然成为通信瓶颈。

② 各节点均维护一张表,以记录本节点所能提供的服务。客户机把请求服务的消息广播出去,那些能提供这些服务的主机就立即把它们的网络地址回送给客户机,客户机一般采用首先返回主机网络地址作为服务主机的地址。

事实上,第一种方法是基于名字服务器的概念。图2-34是一个基于名字服务器的联编系统示意图。

图2-34 基于名字服务器的联编系统示意图

一个服务器发送一个名字给名字服务器(对应于图2-34中的1、2),当客户机进程发出一个远程过程调用时(3),它的存根发送一个请求消息到名字服务器(4)。名字服务器响应请求完成名字与地址的映射后,将服务器主机地址回送客户机存根(5)。

2.联编的实现和执行过程

(1)静态方法:通过三部分(名字服务器、客户机和服务器进程)来实现。

(2)动态方法:联编是在客户机通道和一个服务器进程之间,靠服务器来控制,服务器能分配它的服务器进程激活通道。

关键的问题是,必须知道什么时候发生联编,基于RPC的分布式应用和构造能分成三个阶段。

(1)编译时间(Compile Time):

① 客户机/服务器模块程序设计,像是被预期链接在一起。

② 客户机、服务器与它们各自的存根紧密联系。客户机相对于其存根成为服务器,而服务器相对于其存根成为客户机。

③ 存根在联编和传输过程中对客户机和服务器起保护作用。

④ 理想的存根的生成,靠存根生成器从接口中给出定义。

(2)链接时期(Link Time):

① 一个服务器的可利用性,通过RPC联编本身引出或注册多个调用。

② 一个客户机联编它自己和一个专门服务器靠引入一个调用。

③ 一旦一个联编过程被完成,调用才能发生。

④ 联编不像调用那样频繁地被执行。

(3)调用时期:

① 在OSI表示层提供过程调用的语义。存根使用在它以下的传输层协议传送客户机/服务器之间的变量和可靠的结果。

② 不同的传输层协议能被应用。

③ RPC功能应包括若干控制信息。

2.7.5 远程过程调用设计举例

本节通过一个具体实例说明RPC设计和实现。

1.RPC设计应解决的问题

1)RPC要求网络服务提供支持和ISO、OSI的对照

如前所述,RPC是用户直接在高级语言中使用的一种高层通信机制,它至少应建立在传输层协议之上。因此,一般要求网络提供数据报服务的支持,如图2-35所示。

图2-35 RPC环境和OSI的对照

2)RPC语义问题(Semantics)

RPC和应用本地调用一样,本地调用执行“恰好一次”语义;而RPC的语义就复杂多了。一般来说,在没有节点瘫痪和延迟太长时,请求响应方式RPC可提供如下两种语义:

(1)恰好一次调用语义(Exactly-once)。

(2)至少一次调用语义(At-least-once)。

调用的正常结果意味着服务器执行一次或多次过程调用。为避免产生非预期的结果,该调用应是幂等的,即多次执行该调用与执行一次所得结果一样。

如果出现故障,如调用报文、响应报文丢失,或服务器坏了,为使调用仍能进行又引出两种新的语义:

① 最后一次语义(Last-One),即调用中止意味着服务器执行一次或多次调用,但最终的结果取自最后一次发出的该调用的执行。前几次调用的执行实际上无用,一般称为孤儿(Orphan)。对孤儿处理是RPC中复杂的问题。

② 最多一次调用语义(At-Most-Once),这种语义保证调用的执行或者成功并返回正确结果,或者不产生任何结果。

3)联编(Binding)

客户机发请求,首先要解决服务器定位问题。通过定位和某一专用服务器建立起联系,进行一系列的协同工作和加工处理。

4)在异构型分布式系统中的参数传递

在异构型分布式系统中,存在机器异构、操作系统异构和网络异构等一系列不兼容问题,如RPC的参数在传递前要转换成一种标准代码(如P码或M码),而服务器把标准码变成本地机器的代码,反之亦然。

5)用户接口

大多数RPC采用Birrell和Nelson提出的存根模型(Stub)作为用户接口,这就涉及存根的生成。一种是设计专门的存根产生器,用户在应用程序中对远程过程调用加以说明,诸如给出所请求的服务名、参数、参数类型,然后在编译过程时由存根产生器自动生成相应的代码;另一种采用库函数作为存根,用户直接在应用程序中调用库中的库函数。

2.RPC的设计与组成

下面通过一个具体例子RTU来说明RPC设计。RTU是Masscomp计算机上的实时UNIX,其中RPC为该系统的网络文件系统NFS提供通信支持,使NFS与机器、操作系统无关。

1)RPC的组成

(1)RPC由下列4部分组成。

① 外部数据表示(简称为XDR)。它的功能是完成异种机之间的数据转换工作。它有固定的协议规范,其主要特点是,任何数据类型均以4个字节为单位表示数。

② 身份鉴别(Authentication)。它主要是为网络文件系统提供一种服务,用户鉴别、存取控制、权限检查,安全和访问控制都可以建立在此之上。

③ 客户机(Client)。这部分提供函数调用,使用户能在程序中发RPC请求和接收返回结果。

④ 服务器(Server)。这部分使服务器能提供实现服务功能,并可接收RPC请求及返回结果给用户机。

(2)三层接口如下。

① 最高层——这一层RPC接口对程序员是透明的,调用者不知道使用了RPC还是调用了本地的一个函数。

② 中间层——这一层提供下列三个函数。

regesterrpc( ):用于服务器一方注册服务。

svc-run( ):等待接收RPC请求并执行。

call-rpc( ):客户机发出RPC调用。

③ 最低层——这一层允许程序员改动RPC库函数中的所有默认值,明显地使用Socket套接字来传递RPC信息,其编程也是最复杂的。

(3)对RPC的两个扩充。RTU/RPC中还扩充增加了广播RPC和批处理RPC(Broadcast RPC & Batching RPC),只有超级用户才能发广播RPC。批处理RPC是将RPC报文放置在一个对所希望的服务器进行调用的“管道”中,并假设:

① 管道中的每个RPC调用都不要求从服务器那里得到响应,并且服务器也不发相应信息。

② 调用的管道是由诸如TCP/IP这样的可靠字符流传输装置传送的。

由于服务器对每次调用无需响应,所以客户机可以在服务器执行以前的调用时并行地发出新的调用;而且,建立在TCP/IP之上的RPC可以缓冲许多调用,然后用一次Write( )系统调用发给服务器。这种重叠执行可以大大减轻客户机和服务器进程IPC的负担,以及一系列调用总开销。

2)RPC的几个概念

(1)流(Stream)。流是一块数据存在实体的抽象,是各种存储介质(内存、I/O、外存)的标准接口。RTU/RPC在其XDR部分使用了流,这样做的好处是,XDR的各种操作只在流上实现,而不必对每一种介质都编一套操作,如图2-36所示。

图2-36 流概念

(2)端口(Port)。端口是两台机器进行通信的逻辑通道。

联编(Binding)可以通过端口(Port)进行,在RTU/RPC中,所有服务都注册在一张称为Pmap的表中,并提供一个网络服务Port Mapper,它为客户机提供了从Pmap表上查找任一远程过程的端口号的标准方法。每台机器上的Port Mapper完成端口号—程序号的映射。

客户机为了找到某类网络服务所对应的端口号,可以向服务器一方的Port Mapper发RPC(Port Mapper的端口号是共知的),Port Mapper就返回正确的端口号。

可见,RTU/RPC采用动态和静态相结合的方法定位一个服务,Port Mapper定位是静态的,其他的服务则是动态的。

(3)远程过程。一个远程过程用下列三个参数惟一决定。

① 程序号:定义一类服务的一组过程,如NFS程序号是10003。

② 版本号:允许程序稍加修改不必分配新程序号,并具有兼容性。

③ 过程号:程序组中的一个过程。

(4)套接字(Socket)。它是来源于UNIX 4.2 BSD可用于同一机器之间通信,也可用于网络间通信的一种通用结构。不管使用什么网络(驱动程序)和协议层使用什么协议,对客户机和服务器来说,它们对应的是套接字,它们各自的Socket也是两者之间通信的端点,如图2-37所示。

图2-37 套接字模型

3)RPC的工作流程

RPC的工作流程图如图2-38所示。在图2-38中,服务器返回结果的过程没有表示,具体情况和上述情况相类似,只是把请求报文改成响应报文而已。

图2-38 RTU/RPC的工作流程图

3.RTU/RPC的实现

1)XDR的实现(External Data Representation,外部数据表示)

(1)XDR操作是在流上进行的。XDR句柄的内容如图2-39所示,其中操作类型有下列三种:

图2-39 XDR句柄的内容

ENCODE——由本地数据→XDR。

DECODE——由XDR→本地数据。

FREE——释放空间。

① 由本地机器数据表示转换成XDR时,用ENCODE操作。

② 由XDR转换回本机器数据时,用DECODE。

③ FREE把空间释放。操作向量表含有各种操作的(X-get long)入口地址。私用数据区则对应具体的流,可在创造XDR句柄时确定。

(2)涉及XDR的库函数有三类:

原始类—char,int,float,int short,double,unsigned int。

复合类—string array,unsigned + byte array,any array。

指针类—xdr-reference( ),XDR-pointer,…

① 原始类—这类函数转换C语言中的简单类型。每个函数具有以下形式:

            xdr-xxx (xdrs,datap)
            XDR*xdrs;/*xdrs为XDR句柄指针*/
            XXX*datap;/*datap指向转换对象*/

其中,xdrs为XDR句柄指针,datap为指向转换对象的指针,xxx代表转换的数据类型。原始类XDR函数流程图如图2-40所示。

图2-40 原始类XDR函数流程图

② 复合类XDR函数。这类函数的转换对象包括string、bytearray,这类函数大都由简单类型重复构成,因此只要连续调用原始类XDR函数即可完成转换。

③ 指针类,如函数Xdr-reference( ),定义如下:

xdr-reference(xdrs,PP,size,proc)

其中,PP是欲转换结构指针的地址,size是该结构的大小,proc是转换该结构的XDR函数的入口,在ENCODE时,直接调用proc即可转换该结构;在DECODE时,则要申请空间以容纳转换过来的结构,并使*PP指向它。

有了以上三类XDR函数,用户可以编写转换任意自定义类型的XDR函数。

2)身份鉴别的实现

身份鉴别主要为网络文件系统和分布式系统提供一种安全访问控制服务,结构opaque-auth是描述身份鉴别信息的框架:

            struct opaque-auth{
              cnum-t oa-flavor;/*flavor of auth*/
              caddr-t oa-base; /*addr of more auth*/
              u-int oa-length;  /*起始地址*/
            }

程序第一项oa-flavor是鉴别的类型,有三类:

            enum auth_flavor{
              AUTH-NULL=0  (用于调用者和服务器都不关心各自身份)
              AUTH-UNIX=1  (想从UNIX系统中来辨认身份)
              AUTH-SHORT=2 (服务器响应时才启用,它把与Client身份相匹配的opague-auth
                              传送回去)
              }

第二项oa-base是描述新类型的结构起始地址,描述用于除了上述三种类型以外的鉴别方式。

第三项oa-length是这个结构的长度。

Auth是一个句柄,它是由auth kern-create创建的。它的实现很简单,先为AUTH句柄申请空间,再填上鉴别身份的信息即可。

3)客户机的实现(Client)

(1)RPC报文。RPC报文由下面的结构定义:

            Struct  rpc-msg{
              U-long rm_xid;/*transaction id*/
              enum msg-type rm-direction;/*报文类型*/
              anion{
                Struct call-body RM-cmb /*调用报文*/
                Struct reply-body RM-rmb;
                  }ru;/*响应报文*/
              }

其中,第一项rm_xid的目的是,使服务器返回结果能被请求该服务的客户机收到,以与同一机器上的其他客户机加以区别。方法是,调用者在其RPC报文中给rm-xid设置惟一值,而服务器从调用报文中取出rm-xid,再原封不动地放入响应报文中。这样,调用者就可以取出与它具有相同rm-xid的响应报文。

第二项是报文类型,调用和响应时定义如下:

            enum msg-type{
              call=0
              REPLY=1
            }

它还是第三项ru的选择开关。

当rm-direction为Call时,ru为调用报文RM-cmb;当rm-direction为Reply时,ru为响应报文RM-rmb。

(2)Client句柄。Client句柄有三项(如图2-41所示)。

图2-41 Client句柄

cl-ops包含一些操作。最重要的是cl-call( ),顾客就是通过这个函数发出RPC的。private是私用数据区。

客户机的工作进程见前面的RPC工作流程图。客户机在创建Client句柄的同时创建一个套接字。RPC报文从这套接字发出和在这套接字上等待响应报文。

4)服务器的实现

服务器主要有两部分工作:一是注册服务,二是当RPC请求到达时,调用相应的过程。服务器的工作流程如图2-42所示。

图2-42 服务器的工作流程

(1)注册服务——服务器所提供的服务(即客户机调用的远程过程)注册在一个Pmap表(如图2-43所示)中,为了将对应于[prognum,versnum]的过程注册在Pmap表中,系统提供一个函数svc-register( ),它的流程图如图2-44所示。

图2-43 Pmap表

图2-44 svc-register( )流程图

(2)等待并接收RPC请求。系统创建了一个进程svc-run,它不断查看服务器端的套接字(Socket)中是否有内容。若有,说明有RPC报文到达,则svc-run转去执行所请求的过程,并返回结果;否则,svc-run等待一段时间再查看Socket。若有多个RPC请求到达,则先在Socket保存起来,服务器按FIFO顺序处理。

小结:上面描述了RTU/RPC的具体实现,它是在4.2 BSD基础上,在Kernel部分,RTU/RPC只实现把报文发到套接字或从套接字接收报文,以后的操作由套接字有关操作实现。

RPC的类型:阻塞型发出调用挂起,收到结果再执行,也提供广播和批处理RPC。

服务器执行模型:多个用户请求,排队按FIFO,单线程。

语义:UDP/IP执行一次或多次,无孤儿处理能力。

服务器定位:动静相结合,Port Mapper是固定的,其他由Pmap表来定位。

用户接口:库函数分三层。

异构数据表示:XDR。

RPC交换协议:采用Request-Reply。

传输协议/接口:采用TCP/IP和UDP/IP。

BSD SOCKET支持NFS。

2.7.6 远程过程调用的应用─—NFS

随着分布式系统中RPC的研究,目前已有100多种、10万台计算机运用RPC和NFS。美国Sun公司在工作站基于RPC实现了NFS网络文件系统,目前有几百家计算机厂在自己的产品上都采用NFS协议。IBM、DEC、HP、APPLE、Microsoft都支持NFS,NFS是一个基于RPC的分布式网络环境,其突出的特点不是文件复制,而是文件共享。这是NFS和其他UNIX网络的不同之处。

1.NFS的主要特点

NFS是一个在异构环境下共享文件的分布式网络协议。它采用Client /Server服务方式,其特点如下:

(1)透明信息存取。用户可以直接获得远程文件的数据,而不必了解有关网络的信息。对用户来说,所有NFS安装的文件系统就和本地文件系统一样。读/写本地和远地文件几乎没有区别,因此NFS使信息在网络上真正实现分布式处理。

(2)异构环境适应性。NFS提供灵活的、独立于操作系统平台、发挥各家网络开发软件的长处的一种新型工具,特别适应不同机器和异构环境。XDR是解决异构性的好方法。

(3)易扩充性。NFS网络环境,扩充新的资源或软件,不需要改变现存的工作环境。利用RPC在NFS上提供了一组用于数据交换的扩充协议。

(4)可靠性。NFS的可靠性来自UNIX文件系统的安全性。在NFS协议支持下,当文件服务器协议设计的服务器坏了,重新启动后,客户工作站仍可以继续工作。因为过程调用包含了完成调用的全部信息,服务器出故障时,用户只是感到服务非常慢而已。

(5)高性能。NFS允许用户选用各种不同的配置,或利用无盘工作站,可以使系统获得好的性价比。与UNIX的高度兼容也是SUN NFS广泛应用的原因之一。

2.RPC/XDR协议支持NFS

NFS提供异构环境适用的远程存取能力。这与机器网络协议完全独立。它依赖于XDR协议之上的RPC,按照ISO/OSI的协议,它属于第5层(会话层)。XDR属于表示层。

NFS是在RPC协议的基础上发展起来的,当系统启动以后,nfsd biod是dacmon,执行的命令就是客户机的系统调用。

3.基于NFS的ONC环境

开放网络计算(ONC)包括一组基于NFS网络协议的网络服务,提供下列服务。

(1)NFS服务提供远程文件透明存取。

(2)自动安装或拆卸远程目录Automouter。

(3)Network lock manager提供对NFS存取文件记录值,让用户协调存取公共信息。

(4)NIS网络信息系统。

(5)REX在网络环境下存取远地资源。

(6)NETDisk保证无盘工作站支持ONC/NETDISK无盘的调页对换服务。

4.NFS访问一个文件的流程

客户机可访问位于远地主机的UNIX文件系统中的一个文件。图2-45是访问一个远程文件的流程示意图。

图2-45 访问一个远程文件的流程示意图

首先,用户或应用程序向统一的文件系统接口发出一个系统调用,内核在VFS/VNODE接口中查寻,以便定位所需的文件。如果该文件是一个远程文件,内核重指向NFS文件系统由NFS的特定过程来实现。客户机NFS文件系统运用RPC通信机制,请求服务器NFS文件系统来完成。发出RPC后,在远地主机上的NFS服务例程接到这个请求后执行它。服务例程首先通过服务器上的VFS/VNODE来定位可要求的具体文件系统,在这里是一个UNIX系统。该UNIX文件系统接到请求后,把需要的数据传给NFS服务例程,结果再通过RPC返回给客户主机,就完成了一个文件的调用过程。

2.7.7 消息传递和远程过程调用的对比和进程通信小结

1.对比

对上述两种进程间通信的机制进行对比是必要的,以决定哪个更好和在什么时候选用哪种进程通信的机制更好。这两种机制看起来很类似。例如,消息传递看起来像RPC,在V-System中(Cheriton,1988年)的消息传递现在称为RPC,而在Amoeba中称为消息传递。

应指出:从客户机进程的观点来看,远程过程调用非常类似于远程约会。因为两者都卷入一个封锁调用在两个方向上的参数传送。但是,不同之处在两个通信系统中是很明显的,在机制的实现上、在传送层上和使用模式上都不同。

对比远程过程调用和消息传送,前者的主要的优点是,一个远程过程调用接口很容易实现文件化,像是一系列过程具有参数和结果。从接口的规范看,它可自动生成编码,遮蔽所有程序页消息的细节。

另外,消息传递机制提供的灵活性在RPC中很难找到。但是,这种灵活性是在消息传送接口上文件化地传送的,其成本高。

两者在分布式系统中都广泛地应用,在不同的系统中都强调了各自的优越性。有一项研究包含了两种机制的对比,即在PDP计算机上,StarMod系统和Charlotte系统。

两者对比从一个进程到另一进程的发送时间,RPC端口调用要求更大的开销,由如下因素造成。

(1)在Charlotte,下层协议是一个分层协议,趋向于引入考虑开销。

(2)Charlotte用C语言写成,StarMod用Modula语言生成,编码的效率是一个因素。

(3)两个内核KeVnel是不同的,一个强调的是高性能,另一个强调的是简单。

2.进程通信小结

分布式操作系统运行在网络环境下的所有计算机上而构成分布式计算机系统。因为在系统中没有共享存储器,其进程通信的机制靠消息传递,这意味着高性能的进程间通信是分布式系统的最关键问题。因为需要提供高速的数据交换,所以这种高速数据的交换依靠适当的进程通信原语和支持通信原语的传送协议。

下面列出三种远程进程间通信的原语:

(1)消息传递和高级消息传递。

(2)远程过程调用(RPC)。

(3)执程或事务处理(Transaction)。

以上三种原理分别基于不同的基本概念。

消息传递是集中式系统进程间通信的扩展。它的基本原语是从客户机进程到服务器进程之间实现单方向的通信。

远程进程间通信的原语的类型如下。

(1)封锁执行或非封锁执行类型(执行调用不延迟)。

(2)缓冲和非缓冲型。对于缓冲型原语,在发送和接收之间,消息被缓冲。非缓冲方式有时也称为约会(Rendezvous),有些同步的条件被满足。

(3)可靠与不可靠型。对于可靠型原语,当数据提交时,是可靠的;否则或消息未被复制,或发生了故障。

构造的原语可以是双向的信息流。发送者和接收者必须被同步。这种同步依靠发送操作的语义。

消息发送能用于单一数据报或多个数据报。后者要求提供可靠的提交和恢复。进程间通信靠直接发送消息从一个进程到另一个进程的端口(Port)。链接Link也能用来通信,或是单一链接(像是单向通信通路),或是双向链接定义(像是双向通信路径)。因为Link是面向链接的通信系统,所以是有它自己的优缺点。

当发送一个消息时,一个发送者必须规定要发送的一个专门的进程或一组进程,或能指向所有的进程。发送者可能不期待任何响应,或一个专门响应,或一组响应,或所有目的节点发来的响应。

RPC意味着发送者可将进程从一个计算机上自动调用到另一个计算机上,并不需要知道该过程是在本地还是远地,即具有透明性。

RPC支持的通信可以是在一个客户机和一个服务器之间或在多个客户机和多个服务器之间,因为有些系统不涉及分布式语言。RPC只是描述传送的协议。

远程过程调用要求的是两个远地进程之间的语言级数据结构的传送。为了这个目的,RPC对参数进行组装,把参量表汇集在一起形成一个消息。

用RPC机制可以屏蔽从客户机到服务器机制的具体细节。这意味着需要在客户机和服务器之间进行联编。

分布式系统是非常可靠的和很坚定的。这是因为在不同的分布式节点上提供冗余资源是可能的。一个单一通信不能总是用来提供两个进程之间的互相作用。在这情况下,执程(Transaction)的概念是很方便的。在分布式系统中,基于执程模型的消息交换依靠套接字(Socket),它是在网络上可寻址的实体。

如果进程通信的能力和存储管理紧密结合,会使分布式系统的性能大为改善。这种进程通信提供的性能会超过传统的进程通信系统。