2.3.1 体系结构元素
为了理解一个分布式系统的基础构建块,有必要考虑下面四个关键问题:
- 在分布式系统中进行通信的实体是什么?
- 它们如何通信,特别是使用什么通信范型?
- 它们在整个体系结构中扮演什么(可能改变的)角色,承担什么责任?
- 它们怎样被映射到物理分布式基础设施上(它们被放置在哪里)?
通信实体 上述前两个问题是理解分布式系统的关键;什么是通信和这些实体如何相互通信为分布式系统开发者定义了一个丰富的设计空间。它对从面向系统和面向问题的角度解决第一个问题是有帮助的。
从系统的观点,回答通常是非常清楚的,这是因为在一个分布式系统中通信的实体通常是进程,这导致普遍地把分布式系统看成是带有恰当进程间通信范型的多个进程(如在第4章中讨论的),有两个注意事项:
- 在一些原始环境中,例如传感器网络,基本的操作系统可能不支持进程抽象(或甚至任何形式的隔离),因此在这些系统中通信的实体是结点。
- 在大多数分布式系统环境中,用线程补充进程,所以,严格说来,通信的末端是线程。
在某个层面上,这对建模一个分布式系统是足够的,2.4节考虑的基础模型也确实采用了这个观点。然而,从编程的观点来看,这还不够,更多面向问题的抽象已经被提出:
对象:对象已被引入以便在分布式系统中使用面向对象的方法(包括面向对象的设计和面向对象的编程语言)。在分布式面向对象的方法中,一个计算由若干交互的对象组成,这些对象代表分解给定问题领域的自然单元。对象通过接口被访问,用一个相关的接口定义语言(IDL)提供定义在一个对象上的方法的规约。分布式对象已经成为分布式系统研究的一个主要领域,第5章和第8章将进一步讨论这个话题。
组件:因为对象的引入,许多重要的问题已被认为与分布式对象有关,组件技术的出现及使用是对这些弱点的一个直接响应。组件类似于对象,因为它们为构造分布式系统提供面向问题的抽象,也是通过接口被访问。关键的区别在于组件不仅指定其(提供的)接口而且给出关于其他组件/接口的假设,其他组件/接口是组件完成它的功能必须有的。换句话说,组件使得所有依赖显式化,为系统的构造提供一个更完整的合约。这个合约化的方法鼓励和促进第三方开发组件,42也通过去除隐含的依赖提升了一个更纯粹的组合化方法来构造分布式系统。基于组件的中间件经常对关键领域如部署和服务器方编程支持提供额外的支持[Heineman and Councill 2001]。关于基于组件方法的进一步细节请参见第8章。
Web服务:Web服务代表开发分布式系统的第三种重要的范型[Alonso et al.2004]。Web服务与对象和组件紧密相关,也是采取基于行为封装和通过接口访问的方法。但是,相比而言,通过利用Web标准表示和发现服务,Web服务本质上是被集成到万维网(即W3C)的。W3C(World Wide Web)联盟把Web服务定义成:
一个软件应用,通过URI被辨识,它的接口和绑定能作为XML制品被定义、描述和发现。一个Web服务通过在基于互联网的协议上利用基于XML的消息交换支持与其他软件代理的直接交互。
换句话说,Web服务采用的基于Web的技术在一定程度上定义了Web服务。另一个重要的区别来源于技术使用的风格。对象和组件经常在一个组织内部使用,用于开发紧耦合的应用,但Web服务本身通常被看成完整的服务,它们可以组合起来获得增值服务,它们经常跨组织边界,因此可以实现业务到业务的集成。Web服务可以由不同的提供商用不同的底层技术实现。Web服务将在第9章做进一步的探讨。
通信范型 我们现在转向在分布式系统中实体如何通信,考虑三种通信范型:
- 进程间通信;
- 远程调用;
- 间接通信。
进程间通信指的是用于分布式系统进程之间通信的相对底层的支持,包括消息传递原语、直接访问由互联网协议提供的API(套接字编程)和对多播通信的支持。第4章将详细讨论这样的服务。
远程调用代表分布式系统中最常见的通信范型,覆盖一系列分布式系统中通信实体之间基于双向交换的技术,包括调用远程操作、过程或方法。进一步的定义参见下面内容(详细讨论见第5章):
请求-应答协议是一个有效的模式,它加在一个底层消息传递服务之上,用于支持客户-服务器计算。特别的,43这样的协议通常涉及一对消息的交换,消息从客户到服务器,接着从服务器返回客户,第一个消息包含在服务器端执行的操作的编码,然后是保存相关参数的字节数组,第二个消息包含操作的结果,它也被编码成字节数组。这种范型相对原始,实际上仅被用于嵌入式系统,对嵌入式系统来说性能是至关重要的。这个方法也被用在5.2节描述的HTTP协议中。正如下面讨论的,大多数分布式系统将选择使用远程过程调用或者远程方法调用,但注意底层的请求-应答交换支持两种方法。
远程过程调用(Remote Procedure Call,RPC)的概念,最初由Birrell和Nelson[1984]提出,代表了分布式计算中的一个主要突破。在RPC中,远程计算机上进程中的过程能被调用,好像它们是在本地地址空间中的过程一样。底层RPC系统隐藏了分布的重要方面,包括参数和结果的编码和解码、消息的传递和保持过程调用所要求的语义。这个方法直接而且得体地支持了客户-服务器计算,其中,服务器通过一个服务接口提供一套操作,当这些操作本地可用时客户直接调用这些操作。因此,RPC系统(在最低程度上)提供访问和位置透明性。
远程方法调用(Remote Method Invocation,RMI)非常类似于远程过程调用,但它应用于分布式对象的环境。用这种方法,一个发起调用的对象能调用一个远程对象中的方法。与RPC一样,底层的细节都对用户隐藏。不过,通过支持对象标识和在远程调用中传递对象标识符作为参数,RMI实现做得更多。它们也从与面向对象语言(见第5章相关讨论)的紧密集成中获得更多的好处。
上述技术具有一个共同点:通信代表发送者和接收者之间的双向关系,其中,发送者显式地把消息/调用送往相关的接收者。接收者通常了解发送者的标识,在大多数情况下,双方必须在同时存在。相比而言,已经出现若干技术,这些技术支持间接通信,通过第三个实体,允许在发送者和接收者之间的深度解耦合。尤其是:
- 发送者不需要知道他们正在发送给谁(空间解耦合)。
- 发送者和接收者不需要同时存在(时间解耦合)。
第6章将详细讨论间接通信。
间接通信的关键技术包括:
组通信:组通信涉及消息传递给若干接收者,因此是支持一对多通信的多方通信范型。组通信依赖组抽象,44一个组在系统中用一个组标识符表示。接收方通过加入组,就能选择性接收发送到组的消息。发送者通过组标识符发送消息给组,因此,不需要知道消息的接收者。组通常也要维护组成员,具有处理组成员故障的机制。
发布-订阅系统:许多系统,例如第1章中金融贸易的例子,被归类于信息分发系统,其中,大量生产者(或发布者)为大量的消费者(或订阅者)发布他们感兴趣的信息项(事件)。采用前述的任一核心通信范型来实现这个需求是复杂且低效的,因此,出现了发布-订阅系统(有时也叫分布式基于事件的系统)用于满足此项重要需求[Muhl et al.2006]。发布-订阅系统共享同一个关键的特征,即提供一个中间服务,有效确保由生产者生成的信息被路由到需要这个信息的消费者。
消息队列:虽然发布-订阅系统提供一种一对多风格的通信,但消息队列提供了点对点服务,其中生产者进程能发送消息到一个指定的队列,消费者进程能从队列中接收消息,或被通知队列里有新消息到达。因此,队列是生产者和消费者进程的中介。
元组空间:元组空间提供了进一步的间接通信服务,并支持这样的模型——进程能把任意的结构化数据项(称为元组)放到一个持久元组空间,其他进程可以指定感兴趣的模式,从而可以在元组空间读或者删除元组。因为元组空间是持久的,读操作者和写操作者不需要同时存在。这种风格的编程,也被称为生成通信,由Gelernter[1985]作为一种并行编程范型引入。已经开发了不少分布式实现,采用了客户-服务器-风格的实现或采用了更分散的对等方法。
分布式共享内存:分布式共享内存(Distributed Shared Memory,DSM)系统提供一种抽象,用于支持在不共享物理内存的进程之间共享数据。提供给程序员的是一套熟悉的读或写(共享)数据结构的抽象,就好像这些数据在程序员自己本地的地址空间一样,从而提供了高层的分布透明性。基本的基**础设施必须确保以及时的方式提供副本,也必须处理与数据同步和一致性相关的问题。分布式共享内存的概述在第6章中介绍。
图2-2总结了到目前为止讨论的体系结构。
通信实体(什么在通信)通信范型(它们怎样通信)面向系统的实体面向问题的实体进程间通信远程调用间接通信结点对象 消息传递请求-应答组通信进程组件 套接字 RPC发布-订阅Web服务多播 RMI消息队列元组空间DSM
角色和责任 在一个分布式系统中,进程,或者说,对象、组件、服务,包括Web服务(为简单起见,我们在本节中使用术语“进程”)相互交互完成一个有用的活动,例如支持一次聊天会话。在这样做的时候,进程扮演给定的角色,45在建立所采用的整体体系结构时,这些角色是基本的。本节我们考察两种起源于单个进程角色的体系结构风格:客户-服务器风格和对等风格。
客户-服务器:这是讨论分布式系统时最常引用的体系结构。它是历史上最重要的体系结构,现在仍被广泛地使用。图2-3给出了一个简单的结构,其中,进程扮演服务器和客户的角色。特别是,为了访问服务器管理的共享资源,客户进程可以与不同主机上的服务器进程交互。
如图2-3所示,一台服务器也可以是其他服务器的客户。例如,Web服务器通常是管理存储Web页面文件的本地文件服务器的客户。Web服务器和大多数其他互联网服务是DNS服务的客户,DNS服务用于将互联网域名翻译成网络地址。另一个与Web相关的例子是搜索引擎,搜索引擎能让用户通过互联网查看Web页面上可用的信息汇总。这些信息汇总通过称为“Web抓取”的程序形成,该程序在搜索引擎站点以后台方式运行,利用HTTP请求访问互联网上的Web服务器。因此,搜索引擎既是服务器又是客户:它回答来自浏览器客户的查询,并且运行作为其他Web服务器客户的Web抓取程序。在这个例子中,服务器任务(对用户查询的回答)和Web抓取的任务(向其他Web服务器发送请求)是完全独立的,很少需要同步它们,它们可以并行运行。事实上,一个典型的搜索引擎正常情况下包含许多并发执行的线程,一些线程为它的客户服务,另一些线程运行Web抓取程序。练习2.5将请读者考虑这种类型的并发搜索引擎会出现的同步问题。46
对等体系结构:在这种体系结构中,涉及一项任务或活动的所有进程扮演相同的角色,作为对等方进行协作交互,不区分客户和服务器或运行它们的计算机。在实践中,所有的参与进程运行相同的程序并且相互之间提供相同的接口集合。虽然客户-服务器模型为数据和其他资源的共享提供了一个直接和相对简单的方法,但客户-服务器模型的伸缩性比较差。将一个服务放在单个地址中意味着集中化地提供服务和管理,它的伸缩性不会超过提供服务的计算机的能力和该计算机所在网络连接的带宽。
针对这个问题,已经形成了一系列的放置策略(见下面关于“放置”的讨论),但它们都没有解决基本问题——如何将共享资源进行更广泛的分布,以便将访问资源带来的计算和通信负载分散到大量的计算机和网络链接中。促使对等系统发展的主要观点是一个服务的用户所拥有的网络和计算资源也能被投入使用以支持那个服务。这产生有益的结果:可用于运行服务的资源随用户数而增加。
今天台式计算机具有的硬件容量和操作系统功能已经超过了以前的服务器,而且大多数计算机配备有随时可用的宽带网络连接。对等体系结构的目的是利用大量参与计算机的资源(数据和硬件)来完成某个给定的任务或活动。对等应用和对等系统已经被成功地构造出来,使得无数计算机能访问它们共同存储和管理的数据及其他资源。最早的系统之一是共享数字音乐文件的Napster应用程序。虽然它不是一个纯粹的对等体系结构(而且由于其他非体系结构的原因而变得声名狼藉),但它验证了对等系统的可行性,并使体系结构模型向多个有价值的方向发展。最近一个广泛使用的实例是BitTorrent文件共享系统(关于它的深入讨论见20.6.2节)。
图2-4a说明了对等应用的形式。应用由大量运行在独立计算机上的对等进程组成,进程之间的通信模式完全依赖于对应用的需求。大量数据对象被共享,单个计算机只保存一小部分应用数据库,访问对象的存储、处理和通信负载被分布到多个计算机和网络链接中。每个对象在几个计算机中被复制,以便以后分散负载,并在某个计算机断链时仍能正常工作(这在对等系统针对的大型异构网络中是不可避免的)。在众多计算机上放置对象并检索,同时维护这些对象的副本,这种应用需求使得对等体系结构本质上比客户-服务器体系结构要复杂得多。
对等应用和支持对等应用的中间件的开发将在第10章中深入介绍。
放置 最后要考虑的问题是诸如对象或服务这样的实体是怎样映射到底层的物理分布式基础设施上的,物理分布式基础设施由大量的机器组成,这些机器通过一个任意复杂的网络互联。从决定分布式系统特性的角度而言,放置是关键的,这些特性大多数与性能相关,也包括其他特性如可靠性和安全性。
从机器和机器内部进程的角度看,在哪里放置一个给定客户或服务器的问题是需要仔细设计的。放置需要考虑实体间的通信模式、给定机器的可靠性和它们当前的负载、不同机器之间的通信质量等。必须用有说服力的应用知识来确定放置,有些通用的指导方针可以用来获得一个优化的解决方案。因此,我们主要关注下列放置策略,它们能显著地改变一个给定设计的特征(我们在2.3.2节又回到关于物理基础设施映射的关键问题,那里,我们主要考察层次化的体系结构):
- 将服务映射到多个服务器;
- 缓存;
- 移动代码;
- 移动代理。
将服务映射到多个服务器:服务可实现成在一个单独主机上的几个服务器进程,在必要时进行交互以便为客户进程提供服务(参见图2-4b)。服务器可以将服务所基于的对象集分区,然后将这些分区分布到各个服务器上;或者服务器可以在几个主机上维护复制的对象集。这两种选择可用下列例子说明。
Web就是一个常见的将数据分区的例子,其中的每个Web服务器管理自己的资源集。用户可以利用浏览器访问任一个服务器上的资源。
一个基于复制数据的服务是Sun网络信息服务(Network Information Service,NIS)。它使得LAN中的计算机能在用户登录时访问到相同的用户认证数据。每个NIS服务器有它自己的口令文件副本,该副本记录了用户登录名和加密的口令清单。第18章将详细讨论复制技术。
多服务器体系结构中紧耦合程度更高的是第1章所介绍的集群。一个集群最多可用数以千计的商用处理主板构成,可在这些主板上对服务处理进行分区或复制。
缓存:缓存用于存储最近使用的数据对象,这些被存储的数据对象比对象本身更靠近一个客户或特定的一组客户。当服务器接收一个新对象时,就将它存入缓存,必要的时候会替换缓存中已存在的对象。当客户进程需要一个对象时,缓存服务首先检查缓存,如果缓存中有最新的拷贝可用就提供缓存中的对象;如果缓存没有可用的对象,才去取一个最新的拷贝。每个客户都可以配置缓存或者将缓存放置在由几个客户共享的代理服务器上。
缓存在实际工作中被广泛使用。Web浏览器维护一个缓存,它在客户本地的文件系统中存放最近访问的Web页面和其他Web资源,并在显示前用一个特殊的HTTP请求到原来的服务器上检查被缓存的页面是否是最新的。Web代理服务器(见图2-5)49为一个或多个地点的客户机提供共享的存放Web资源的缓存。代理服务器的目的是通过减少广域网和Web服务器的负载,提高服务的可用性和性能。代理服务器能承担其他角色,例如它们可以用于通过防火墙访问远程Web服务器。
移动代码:第1章介绍了移动代码。applet是一个众所周知的并被广泛使用的移动代码例子,即运行浏览器的用户选择了一个到applet的链接,applet的代码存储在Web服务器上,将applet的代码下载到浏览器并在浏览器端运行,如图2-6所示。在本地运行下载的代码的好处是能够提供良好的交互响应,因为它不受与网络通信相关的延迟或带宽变化的影响。
访问服务意味着运行能调用服务所提供的操作代码。一些服务可能进行了标准化,所以能用一个已有的且众所周知的应用对其进行访问——Web就是一个大家很熟悉的例子,但有些Web站点使用了在标准浏览器中找不到的功能,还要求下载额外的代码(例如,用额外的代码与服务器通信)。考虑一个应用,该应用要求用户应该与发生在服务器信息源端的变化保持一致。这一功能不能通过与Web服务器的正常交互获得,因为那种交互总是由客户发起。解决方案是使用另外一种被称为推模式操作的软件,在这种方式下由服务器而不是客户发起交互。例如,股票经纪人可能提供一个定制的服务来通知顾客股票价格的变动。为了使用这个服务,每个顾客都要下载一个特殊的、能接收来自经纪人服务器的更新的applet,该applet可向用户显示更新,还可能自动地完成买卖操作,这些操作是根据顾客设置的、存储在顾客本地计算机上的条件而触发的。
移动代码对目的计算机中的本地资源而言是一个潜在的安全威胁。因此,浏览器采用11.1.1节讨论的方案对applet访问本地资源进行了限制。
移动代理:移动代理是一个运行的程序(包括代码和数据),它从一台计算机移动到网络上的另一台计算机,代表某人完成诸如信息搜集之类的任务,最后返回结果。一个移动代理可能多次调用所访问地点的本地资源——例如,50访问一个数据库条目。如果将这种体系结构与对某些资源进行远程调用的静态客户相比,那么后者可能会传输大量的数据,前者通过用本地调用替换远程调用而降低了通信开销和时间。
移动代理可用于安装和维护一个组织内部的计算机软件或通过访问每个销售商的站点并执行一系列数据库操作,来比较多个销售商的产品价格。一个类似想法的早期例子是在Xerox PARC开发的所谓蠕虫程序[Shoch and Hupp 1982],该程序利用空闲的计算机完成密集型计算。
移动代理(和移动代码一样)对所访问的计算机上的资源而言是一个潜在的安全威胁。接收一个移动代理的环境应该根据代理所代表的用户的身份决定允许使用哪些本地资源——它们的身份必须以安全的方式被包含在移动代理的代码和数据中。另外,移动代理自身是脆弱的——如果它们访问所需信息的要求被拒绝,那么它们可能完不成任务。由移动代理完成的任务可以通过其他手段完成。例如,需要经由互联网访问Web服务器上资源的Web抓取程序可以通过远程调用服务器进程而运行得相当成功。基于上述理由,移动代理的适用性是有限的。