通信
当今只有少数媒体和大型软件系统在单机上运行——绝大多数都使用计算机网络。原因如下:
·分布式系统能够更好地实现网络资源的共享和利用。
·快速但价格昂贵的服务器可以承担中央服务(例如数据库管理系统),而花费不多的工作站可以远程访问这些服务。
·公司内部工作本质上是分布式的,因此实现业务逻辑的分布式软件系统与这种工作组织相匹配。
这种应用的分布式有一个重要的先决条件。分布式的子系统必须要相互协作,因此需要一种相互通信的手段。为了降低分布式系统组件及通信机制之间的耦合,我们在封装和位置透明性两个方面着手,封装意味着对用户隐藏底层通信机制的细节,位置透明性可以让你的应用程序不知道物理位置而访问远程组件。以下针对这两方面的模式:
·转发器——接收器(Forwarder - Receiver)设计模式为对等交互模型的软件系统提供了透明的进程间通信。它引入转发器和接收器用于从下层通信机制中分离开对等体。
·客户机——分配器——服务器(Client - Dispatcher - Server)设计模式在客户机与服务器之间引入一个中间层——分配器组件。通过名字服务器实现位置透明性,并且隐藏客户机与服务器间建立通信连接的细节。
转发器——接收器设计模式提供了封装,而客户机——分配器——服务器模式提供了位置透明性。如果需要支持封装和位置透明性这两个方面,可以将这两种模式相结合。
转发器——接收器
用于建立分布式应用的最常用方法是利用现有的低层进程间通信(IPC)机制,如TCP/IP、套接字或消息队列。几乎所有的操作系统都提供这些机制,当它们与高层机制(如远程过程调用)相比时是非常有效的。然而这些低层机制通常会引入下层操作系统与网络协议间的相关性。通过使用一种特殊的IPC机制,最后的解决方案限制了可移植性,束缚了支持异构环境系统的能力,并且使以后更改IPC机制变得困难。
转发器——接收器模式在权衡如下强制条件时是有用的:
·系统应该具备通信机制可交换性。
·组件合作遵循一种对等模型,在此模型中发送者只需要知道其接收器的名字。
·对等体间的通信不应对系统性能产生主要影响。
结构
转发器——接收器设计模式由三种组件构成:转发器、接收器和对等体:
对等体组件负责应用任务。要实现它们的任务,对等体需要与其他的对等体通信。它们可能处于不同的进程甚至不同的机器上。每一个对等体知道需要进行通信的远程对等体的名字。它使用转发器向其他对等体发送消息并且使用接收器接收由其他对等体传送来的消息,这些消息或者是一个对等体发送给远程对等体的请求或者是对等体传送到请求发起者的响应。
转发器组件路跨越进程边界发送消息。一个转发器提供一个通用接口,该接口是一个特殊IPC机制的抽象,并且包括列集消息功能和传送消息的功能。转发器还包含从名字到物理地址的映射。当转发器向远程对等体发送消息时,该转发器通过使用其名字到地址的映射来确定接收端的物理地址。在发送的消息中转发器指定自己对等体的名字,这样远程对等体能够向消息发起者发送一个响应。
接收器组件负责接收消息。一个接收器提供一个通用接口,该接口是一个特殊IPC机制的抽象。它包括接收消息的功能和散集消息的功能。
实现
1)指定名字到地址的映射。因为对等体通过名字引用其他的对等体,所以需要引入一个适当的名字空间。名字空间定义在给定语境中名字必须符合的规则和约束。
一个名字不一定是指单一地址——它也可以是指一组地址。当一个对等体发送带有表示一组远程对等体的目标名字的消息时,消息被发送给组内每个成员。甚至可以引入一个分层结构使用一组成为另一组的组成员。
2)指定在对等体及转发器间使用的消息协议。该协议规定了转发器收到其对等体信息协议执行同样的任务。
我们还需要远程对等体的转发器与接收器间的通信协议。转发器发送一个远程接收器的消息也包括发送者的名字。
通常要使系统能够处理超时。还需要考虑当通信失效时,接收器与转发器作出什么样的反应。它们也许试图不止一次地发送或接收消息,或者当第一次通信失败时它们报告异常事件的发生。
3)选择通信机制。这个决定主要取决于所采用操作系统中可供使用的通信机制,指定IPC设备时,需要考虑如下几个因素:
·如果效率因素是非常重要的,那么低层机制(如TCP/IP)可以是首选。在使用它们来建造的通信协议中这样的机制效率很高而且很灵活。
·低层机制(如TCP/IP)需要大量的编程工作,并且依赖所使用的平台,这限制了可移植性。如果系统在平台间是可移植的,那么最好使用IPC机制(如套接字)。
4)实现转发器。封装在转发器中跨越进程边界发送消息的所有功能。转发器通过公用接口提供其功能并且封装了特殊IPC机制的细节。
定义一个将名字映射成为物理地址的库。在建立同远程对等体通信链接之前转发器访问这个库,以取回接收者的物理地址。这个库可以是静态预先定义的,也可以是运行期间可改变的,决定每个转发器是否都应具有自己的私有库,或者所有的转发器是否应使用一个公共的对其线程而言是本地的库。
5)实现接收器。封装接收器中用来接收IPC消息的所有功能,给接收器提供一个通用接口,该接口从特殊IPC机制的细节中抽象出来。
由于所有的对等体异步运行,因此必须要决定在消息到达之前接收器是否应该阻塞:
·如果是的话,接收器等待新来的消息。只有在收到消息时它才将控制机返回给其对等体。
·除此之外,应该实现无阻塞的接收器,它允许对等体去指定超时值。如果在指定的时间内消息没有到达,接收器给其对等体返回一个异常。
如果下层IPC机制不支持无阻塞的I/O,则可以在对等体内使用一个独立的线程来处理通信。
接收器内使用不止一个通信信道是另一个重要的设计问题。这样的接收器可以多路分解通信信道——它们处于等待状态直到一个消息到达某个信道,然后将消息返回给其对等体。
6)实现应用对等体。将对等体分割成两个集合——客户机与服务器。
7)实现启动配置。系统启动时,转发器和接收器必须用一个有效的名字到地址的映射进行初始化。引入一个单独的启动例程来创建库并输入所有的名字/地址对。这样的配置例程可以从外部文件读入这些名字/地址对,改变映射时不需要接触到源代码。
优点
1)有效的进程间通信。组件间的通信以对等方式来构建,其中IPC消息的每个转发器都知道其潜在接收器的物理位置。
2)KPC设备的封装。所有具体IPC设备的附属物都被封装在转发器和接收器内。下层IPC机制的改变不会影响应用程序的其他组件,尤其不会影响通过转发器和接收器相互通信的对等体。
不足
1)不能支持灵活的组件重新配置。如果对等体的分布在运行期间变更,那么转发器——接收器系统是很难适应的。这个问题可以通过增加一个分配器组件来解决。