第5章分布式系统模式

在当今的互联世界中,越来越多的企业应用程序跨多个服务器分布和运行、连接到远程数据源和 Web Service,并可通过 Internet 访问。分布式计算功能强大,但也并非没有面临挑战。网络在本质上并不可靠,同本地的进程间通信相比,与远程服务器的通信速度较慢。另外,同时在多台计算机 上运行一个程序可能会导致许多并发和同步问题。

基于实例的协作和基于服务的协议

按照 Business Component Factory(业务组件工厂)的说,分布式计算可以基于两个截然不同的体系结构样式:

  • 基于实例的协作
  • 基于服务的协作

基于实例的协作跨网络边界扩展了面向对象的计算模型。组件可以实例化远程对象实例、四处传递对这些远程对象的引用、调用远程对象的方法以及取消对它们的分配。此方法的优点在于,可以将应用程序内使用的同一个面向对象的编程模型应用于分布式组件。大多数运行时平台都包含对基于实例的协作的支持,以便开发人员 在访问远程对象时不必提供特殊内容,或者相对于访问本地对象,只需提供极少的特殊内容。这就大大简化了分布式解决方案的开发,通常会简化到如下程度:以前位于相同位置的对象可以在部署时进行分布,而无需对应用程序进行任何代码更改。基于实例的协作还使远程对象的使用者能够更加精细地控制远程对象的生存期, 从而让用户更有效地使用远程资源。

但是,基于实例的协作在带来易用性的同时,还因复杂的交互模型以及用户和提供商之间的紧密联系而导致成本增加。基于实例的交互要求远程对象的特定实例可以通过网络找到,这将复杂的生存期和实例管理引入了通信协议中。因此,大多数支持基于实例的协作的平台都 不提供与其他平台的互操作性。

基于服务的协作通过只向潜在使用者公开“类似于管理器”或“类似于协调器”的接口来解决其中的一些挑战。用户可以调用该接口上的方法,但是他们不能控制任何远程对象的生存期。这大大简化了交互,并允许使用支持跨平台互操作的标准协议。

但是,基于服务的协作不能为本地对象和远程对象提供使用面向对象的编程模型时所具备的连续性。这意味着您必须明确跟踪对象之间的会话状态,而在使用基于实例的协作时就不必担心这些。同样,尽管基于标准的协议改善了互操作性,但是它们要求应用程序将应用程序内部数据类型转换成每个通信终端都能够理解的通用格式,而这可能涉及其他转换逻辑。

近链接与远链接

考虑分布式系统的另一种方式就是将每个系统视为通过链接连在一起的处理节点的集合。这些节点代表实际的服务器计算机,而链接代表将这些计算机连在一起的网络。系统内的链接分成两类:近链接或远链接。

近 链接驻留在同一个信任区域中、同一个企业内,它们以可靠方式连接而且不涉及互操作性。远链接包括所有其他链接(包括跨越 Internet 的任何链接)。 如果您的分布式系统仅跨越近链接,则最好使用基于实例的协作。使用基于实例的协作,可以跨计算机边界扩展面向对象的开发能力,同时利用平台的基础结构来优 化速度、导航类型系统并为您操作封送处理细节。此处的技术选项将包括 Microsoft? .NET Framework 中的 .NET Remoting 和 Enterprise Services。

另一方面,如果您的分布式系统跨越远链接,则基于服务的协作通常是较好 的选择。如果与提供“类似于协调器”的接口的服务进行交互,则允许该服务负责实现,而不必让服务用户了解实现细节。服务接口通常返回消息,这比远程过程调 用提供的耦合性要少。最好的消息是那些既包含头信息又包括正文的消息,这允许接收者针对收到的消息自发执行操作。此处的技术选项包括诸如 Web Services 这样的功能。

本章的其余部分将描述通常与基于实例的协作和近链接相关联的模式。第 6 章“服务模式”将进一步介绍通常与基于服务的协作和远链接相关联的模式。

分布式计算所面临的挑战

分布式体系结构的核心是能够调用对象上的方法或者与驻留在不同进程中甚至有可能在不同计算机上的服务进行通信。看起来这似乎不难,但是您必须解决非常多的问题:

  • 如何实例化远程对象?
  • 如果您希望调用现有对象上的方法,那么如何获取对该对象的引用?
  • 网络协议仅传输字节流,而不传输对象。如何才能通过字节流调用方法?
  • 安全性如何?是否每个人都能够调用远程对象上的方法?
  • 大多数网络在本质上都不可靠。如果无法访问远程对象,会出现什么情况?如果远程对象收到方法调用,但是因网络问题而无法发送响应,该怎么办?
  • 调用远程对象比调用本地方法慢得多。您是否希望异步调用远程方法,以便在远程对象处理请求的同时可以继续在本地处理?

问 题不胜枚举。幸运的是,.NET Framework 中的功能解决了其中的大多数问题,使得开发人员在创建分布式应用程序时不必处理太多的细枝末节。这些功能使得远程调用对于程序员几乎是透明的(至少在句法 级别是如此)。但是,这种简化可能存在一定的欺骗性,因为开发人员还必须了解远程通信的一些基本原理,才能写出强大而高效的分布式应用程序。分布式系统模 式群集有助于开发人员在实现分布式应用程序时作出明智的设计决策。

使用分层应用程序

为分布式系统创建易用的基础结构的秘诀是Layered Application 。分布式服务层依赖较低层(如 TCP/IP 堆栈和套接字通信层),但是较低层的细节不会显示在包含应用程序和业务逻辑层的较高层中。这种安排使得应用程序开发人员在较高抽象级别工作时不必考虑诸如 TCP/IP 数据包和网络字节排序之类的细节。它还可以在替换较低层时不对较高层造成任何影响。例如,您不必在应用程序层更改代码,即可切换到另一个传输协议(例如, 使用 HTTP 代替直接使用 TCP/IP)。

便于开发人员进行远程调用的一种方法就是使用 Proxy(代理)[Gamma95]。代理是与客户端对象通信的本地替身。当客户端创建远程对象的实例时,基础结构就会创建一个代理对象,该对象在客户 端看来与远程类型完全相同。当客户端调用该代理对象上的方法时,该代理就会调用远程处理基础结构。远程处理基础结构将请求路由到服务器进程,然后调用服务 器对象,并将结果返回给客户端代理,最后客户端代理将结果传递给客户端对象。由于所有这些操作都是在后台进行的,因此客户端对象可能完全不知道另一个对象 驻留在其他计算机上。这不仅方便了分布式应用程序的开发,而且还允许您在程序开发出来之后再分布对象,而只需对应用程序代码进行很小的改动。

模式概述

分布式系统模式群集强调两个主要概念:远程调用和粗粒度接口。

图 1 分布式系统群集中的模式

远程调用

Broker (代理程序)模式描述如何查找远程对象并调用它的一个方法,而不会将通过网络进行通信的复杂性引入应用程序。此模式为大多数分布式体系结构(包括 .NET Remoting)奠定了基础。

.NET Framework 的指导原则之一就是简化复杂的编程任务,同时不会夺走程序员的控制权。按照该原则,.NET Remoting 提供了大量远程处理模型供开发人员选择,如下面的段落所述。

本地副本

最简单的远程处理模型涉及到按值将对象的副本传递给客户端。以后针对该对象进行的所有方法调用都是真正的本地调用。此模型避免了分布式计算中固有的许多复杂 性,但同时也存在许多缺点。首先,由于您是在自己的进程空间中运行对象的本地副本,因此计算不是真正的分布式计算。其次,由于对对象状态进行的所有更新仅发生在本地,因此它们会丢失。最后,由于对象需要远程资源或者远程对象的提供商希望保护对其内部资源的访问,因此对象通常是远程的。将对象实例复制到本地 进程不仅无法实现这两个目标,而且还会增加因通过远程通道传送整个对象而带来的开销。由于存在上述限制,因此本章仅讨论对象复制的唯一应用:Data Transfer Object (数据传输对象)模式。

服务器激活的对象

与使用远程对象的本地副本相比,直接调用远程对象上的方法是更好的选择。但是,只有当您拥有对远程对象的引用时,才能调用其上的方法。获取对远程对象的引用 要求首先实例化该对象。客户端要求服务器提供该对象的实例,然后服务器返回对远程实例的引用。如果远程对象可被视为服务,则上述过程可以顺畅地工作。例 如,假设有一个用来验证信用卡号的服务。客户端对象提交一个信用卡号并收到一个正的或负的响应,具体情况取决于客户的消费(和偿还)习惯。在本例中,您并 不真正关心远程对象的实例。您只管提交某些数据、接收结果并继续操作。这是“无状态服务”的一个很好的例子。在无状态服务中,每个请求都会使对象继续保持 此前所处的状态。

但是,并非所有远程对象协作都遵循此模型。有时,您希望调用远程对象,以便检索某些可在以后进行远程调用时访问的数据。 您必须确保在随后的调用过程中调用的是同一个对象实例。而且,当您检查完数据后,您将希望取消对该对象的分配以节省服务器内存。利用服务器激活的对象,无 法对对象实例实现这种级别的控制。服务器激活的对象为实例生存期管理仅提供两个替换选项:

  • 针对每次调用创建对象的新实例。
  • 对于所有客户端仅使用远程对象的单个实例(使该对象有效地成为 Singleton)。

如果您希望通过几次功能调用来访问同一远程实例,然后将其扔到垃圾回收器中,则上述任一选项都不合适。

客户端激活的对象

客户端激活的对象使 客户端能够控制远程对象的生存期。客户端几乎可以像实例化本地对象那样实例化远程对象,在客户端删除对该对象实例的所有引用之后,垃圾回收器会删除远程对 象。但是,这种级别的控制成本较高。要使用客户端激活功能,必须复制可由客户端进程访问的程序集。这与各种客户端应该无需进一步设置即可访问远程对象的想 法存在冲突。

但是,您可以通过创建一个服务器激活的对象(作为服务器对象的工厂对象)来达到最佳平衡。此工厂对象创建其他对象的实例。工 厂本身是没有状态的,因此,您可以很方便地将它作为服务器激活的 Singleton 来实现它。随后,所有客户端请求都共享该工厂的同一个实例。因为该工厂对象在远程运行,所以它所实例化的所有对象都是远程对象,但是客户端可以决定在何时 以及在何处实例化它们。

粗粒度接口

跨进程和网络边界调用方法比调用同一操作系统进程中对象上的方法慢得多。

许 多面向对象的设计做法通常倾向于设计带有细粒度接口的对象。这些对象可以拥有许多带有相关 getter 和 setter 的字段以及大量方法,每种方法都封装了一小块粘合在一起的功能。由于这种细粒度特性,所以必须调用大量方法才能实现所需的结果。因为这种细粒度接口方法支 持许多令人满意的应用程序特征(如可维护性、可重复使用性和可测试性),所以对于独立应用程序,这是一种理想选择。

如果使用公开细粒度接 口的对象,则会大大影响应用程序的性能,这是由于细粒度接口要求跨进程和网络边界进行多次方法调用。为了改善性能,远程对象必须公开一个粒度更大的接口。 粗粒度接口公开一组相对较小的独立方法。每种方法通常都代表一段高级功能(如下订单或更新客户)。因为某个方法所需的全部数据都以参数形式传入该方法中, 所以这些方法都被视为独立方法。

Data Transfer Object

The Data Transfer Object 模式将粗粒度接口概念应用于如下问题:在由进程和网络边界隔开的组件之间传递数据。它建议将许多参数替换为一个对象,在该对象中存储远程方法所需的全部数据。该技术对于远程方法返回的数据也非常适用。

有 多种选项可以用来实现数据传输对象 (DTO)。一种方法是为解决方案所需的每种不同类型的 DTO 分别定义一个单独的类。针对所包含的每种数据元素,这些类通常有一个强类型的公共字段(或属性)。为了跨网络或进程边界传输这些对象,这些类都要序列化。 序列化对象被跨边界封送处理,然后在接收端重新建立。此方法的主要优点是性能和类型安全。此方法的封送处理开销最小,DTO 的强类型字段确保类型错误在编译时(而非运行时)即可被捕获。此方法的缺点是需要为每个 DTO 创建一个新类。如果解决方案需要大量 DTO,则与编写和维护这些类相关的工作会非常艰巨。

创建 DTO 的第二种方法是使用一般容器类来保存数据。此方法的常见实现是将类似于 ADO.NET DataSet 的类用作一般容器类。此方法需要两次额外转换。第一次转换发生在发送端,它将应用程序数据转换为适用于DataSet 的形式。第二次转换发生在接收端,它将数据从DataSet 中提取出来以用于客户端应用程序。在某些应用程序中,这些额外的转换可能会影响性能。此方法的另一个不足之处是缺乏类型安全性。如果将客户对象放在发送端 的 DataSet 中,则在接收端上尝试提取顺序对象时会导致运行时错误。此方法的主要优点是不必编写、测试或维护任何额外的类。

ADO.NET 提供了第三个可选选项 - 类型化 DataSet。ADO.NET 提供一种自动生成包装 DataSet 的类型安全包装器的机制。此方法存在与DataSet 方法同样的潜在性能问题,但是应用程序可以受益于类型安全这一优点,并且开发人员不必为每个 DTO 都开发、测试和维护一个单独的类。

时间: 2024-10-17 08:41:04

第5章分布式系统模式的相关文章

第5章分布式系统模式 Broker(代理程序)

许多复杂的软件系统运行在多个处理器或分布式计算机上.将软件分布在多台计算机上的原因有多种,例如: 分布式系统可以利用多个 CPU 或一群低成本计算机的计算能力. 某个软件可能仅在特定计算机上可用. 出于安全考虑,软件的各部分可能必须运行在不同的网段上. 一些服务可能是由业务合作伙伴提供的,并且只能通过 Internet 进行访问. 但是,实现分布式系统是不容易的,因为您必须处理诸如并发性.跨平台连接和不可靠网络连接之类的问题. 影响因素 在构建分布式系统时,必须协调下列影响因素: 虽 然分布式系

第5章分布式系统模式 使用服务器激活对象通过 .NET Remoting 实现 Broker

正在使用 Microsoft? .NET Framework 构建一个需要使用分布式对象的应用程序.您的要求包括能够按值或按引用来传递对象,无论这些对象驻留在同一台计算机上,还是驻留在同一个局域网 (LAN) 中的不同计算机上,或者是驻留在广域网 (WAN) 中的不同计算机上.应用程序不需要您显式控制远程对象的生存期. 关于 .NET Remoting 的背景信息 远 程处理使用对象引用来进行客户端和服务器之间的通信.在服务器激活情况下,客户端使用远程处理基础结构 (Activator.GetO

第5章分布式系统模式 使用客户端激活对象通过 .NET Remoting 实现 Broker

正在 .NET 中构建一个需要使用分布式对象的应用程序,并且分布式对象的生存期由客户端控制.您的要求包括能够按值或按引用来传递对象,无论这些对象驻留在同一台计算 机上,还是驻留在同一个局域网 (LAN) 中的不同计算机上,或者是驻留在广域网 (WAN) 中的不同计算机上. 实现策略 这 种模式为在 .NET Remoting 中实现客户端激活对象提供了两种实现方式.客户端激活对象 (CAO) 和服务器激活对象 (SAO) 之间的主要区别在于,是什么控制着远程对象的生存期.在使用 CAO 的情况下

第5章分布式系统模式 Singleton

上下文 在某些情况下,特定类型的数据需要提供给应用程序中的其他所有对象使用.在大多数情况下,这种类型的数据在系统中还是唯一的.例如,用户界面只能有一个所有应用程序必须访问的鼠标指针.同样,企业解决方案可能用单网关对象作为接口来管理与特定旧系统的连接. 影响因素 以下因素影响这种情况中的系统,在考虑上述问题的解决方案时必须协调这些影响因素: 很多编程语言(例如 Microsoft Visual Basic® 6.0 版或 C++)都支持全局对象的定义.这些对象位于命名空间的根部,应用程序中所有对象

第5章分布式系统模式 Data Transfer Object(数据传输对象)

正在设计一个分布式应用程序,为了满足单个客户端请求,您发现自己对一个远程接口发出了多个调用,而这些调用所增加的响应时间超出了可接受的程度. 影响因素 在与远程对象通信时,请考虑下列需要权衡的因素: 远程调用(那些必须跨越网络的调用)速度缓慢.虽然许多远程调用框架可以隐藏进行远程调用的复杂性,但是它们不能消除发生通信所需的步骤.例如,必须先找到 远程对象位置,而且建立与远程计算机的连接,然后才能将数据串行化为字节流,然后可能进行加密,最后才能将其传输到远程计算机. 在 考虑网络性能时,必须同时考虑

第5章分布式系统模式 在 .NET 中使用 DataSet 实现 Data Transfer Object

要在 .NET Framework 中实现分布式应用程序.客户端应用程序需要显示一个窗体,该窗体要求对 ASP.NET Web Service 进行多个调用以满足单个用户请求.基于性能方面的考虑,我们发现,进行多个调用会降低应用程序性能.为了提高性能,需要通过对 Web Service 进行一次调用就能检索到用户请求所需的所有数据. 背景信息 注意:以下是在 .NET 中使用类型化 DataSet 实现 Data Transfer Object 中所描述的同一个示例应用程序. 下面是一个简化的

第 7 章 门面模式【Facade Pattern】

以下内容出自:<<24种设计模式介绍与6大设计原则>> 好,我们继续讲课.大家都是高智商的人,都写过纸质的信件吧,比如给女朋友写情书什么的,写信的过程大家都还记得吧,先写信的内容,然后写信封,然后把信放到信封中,封好,投递到信箱中进行邮递,这个过程还是比较简单的,虽然简单,这四个步骤都是要跑的呀,信多了还是麻烦,比如到了情人节,为了大海捞针,给十个女孩子发情书,都要这样跑一遍,你不要累死,更别说你要发个广告信啥的,一下子发1 千万封邮件,那不就完蛋了?那怎么办呢?还好,现在邮局开发

设计模式之第6章-迭代器模式(Java实现)

设计模式之第6章-迭代器模式(Java实现) “我已经过时了,就不要讲了吧,现在java自带有迭代器,还有什么好讲的呢?”“虽然已经有了,但是具体细节呢?知道实现机理岂不美哉?”“好吧好吧.”(迭代器闷闷不乐的答应下来.作者吃着小笼包,咂咂嘴道:哼,想偷懒,窗户都没有~). 迭代器模式之自我介绍 正如你们所见,我目前已经没落了,基本上没人会单独写一个迭代器,除非是产品性质的研发,我的定义如下:Provide a way to access the elements of an aggregate

第 12 章 命令模式【Command Pattern】

以下内容出自:<<24种设计模式介绍与6大设计原则>> 今天讲命令模式,这个模式从名字上看就很简单,命令嘛,老大发命令,小兵执行就是了,确实是这个意思,但是更深化了,用模式来描述真是是世界的命令情况.正在看这本书的你,我猜测分为两类:已经工作的和没有工作的,先说没有工作的,那你为啥要看这本书,为了以后工作呗,只要你参见工作,你肯定会待在项目组,那今天我们就以项目组为例子来讲述命令模式. 我是我们部门的项目经理,就是一个项目的头,在中国做项目,项目经理就是什么都要懂,什么都要管,做好