功能的发展:版本化
除了随着用户的数量以及事务的数量而扩展规模外,当新的特性加入时应用系统也需要扩展规模。随着时间的推移,新的任务被添加进来,原有的任务被更新。传统的做法是或者客户进程和组件都需要同时被更新,或者旧的组件必须被保留直到所有的客户进程被更新,当大量的地理上分布的站点和用户在使用系统时,这就成为一个非常费力的管理问题。
DCOM为组件和客户进程提供了灵活的扩展机制。使用COM和DCOM,客户进程能够动态地查询组件的机能。一个COM组件不是将其机能表现为一个简单、统一的方法和属性组,而是对于不同的客户进程表现为不同的形式。使用特定特性的客户进程只需要访问它所需要使用的方法和属性。客户进程也能够同时使用一个组件的多个特性。当新的特性加入组件时,它不会影响不涉及这些特性的老的客户进程。
用这种方法来组织组件,使得我们能够有一种新的方法来发展组件功能:最初的组件表现为诸如COM界面的一套核心特性,这些特性是每个客户进程都需要使用的。当组件需要新的特性时,大多数(甚至是全部)的界面仍然是必须的,我们根本无须更改原来的界面就可以将新的功能和属性放到附加的界面中去。老的用户进程就好象什么事也没发生似的继续访问核心界面。新的客户进程既可以测试新的界面是否存在以便能使用它,也可以仍然只使用原来的界面。
图8 健壮的版本发展
因为在DCOM编程模型中机能被分组放入界面中,你可以设计使用老的服务器程序的新的客户程序,也可以设计使用老的客户程序的新的服务器程序,或者将这些混合起来以便能够适合你的需求和编程资源。使用传统的对象模型时,那怕是对一个方法的细微改动都可能在根本上改变客户和组件之间的协议。在一些模型中,可以将方法加到方法队列的队尾,但是却不能在老的组件上测试新的方法。从网络发展的前景看来,这些事情将会变得越来越复杂:编码以及其它的一些功能典型地依赖于方法和参数的顺序。增加或改动方法和参数也会显著地改变网络协议。DCOM为对象模式和网络协议设计了一个简单、优雅和统一的方法来解决这些问题。
执行性能
如果最初的执行性能不能让人满意的话,可扩展性就不会带来太多好处了。经常考虑到更多更好的硬件会使得应用向下发展是非常有益的,但是这些需求是怎样的呢?这些尖端扩展特性是否有用呢?是否对从COBOL到汇编这每一种语言的支持会危害到系统的执行性能呢?使组件能够在地球的另一面运行的能力是否妨碍了当它和客户在同一个进程中时的执行性能呢?
在COM和DCOM中,客户并不能自己看到服务器,但是除非是在必要的情况下,否则客户进程决不会被系统组件将自己同服务器分开。这种透明性是通过一个简单的思想来实现的:客户进程同组件交互的唯一方式就是通过方法调用。客户进程从一个简单的方法地址表(一个“vtable”)中得到这些方法的地址。当客户进程想要调用一个组件中的某个方法时,它先得到方法的地址,然后调用它。在COM和DCOM模型中调用一个传统的C或汇编函数的唯一开支就是对方法地址的简单查询。如果组件是和客户运行在同一个线程中的过程中组件,那么无需调用任何COM或系统代码就可以直接找到方法的地址,COM仅仅只定义了找到方法地址表的标准。
当用户和组件不是那么靠近──在另一个线程中,在另一个程序中或者在地球另一面的一台机器中时情况又是怎样的呢?COM将它的远程过程调用(RPC)框架代码放到vtable中,然后将每个方法调用打包放到一个标准的缓冲器结构中,这个缓冲器结构将被发送给组件,组件打开包并且重新运行最初的方法调用。从这方面来说,COM提供了一个面向对象的RPC机制。
这种RPC机制的速度有多快呢?下面是需要考虑的不同的性能尺度:
一个“空”方法调用有多快?
“真正的”需要发送和接收数据的方法调用有多快?
在网络上转一圈有多快?
下表显示了COM和DCOM的一些真实的执行性能参数,使我们能够对DCOM和其它的协议的相关的执行性能有一定的了解。
Parameter Size
4 bytes
50 bytes
calls / sec
ms / call
calls / sec
ms / call
"Pentium®,,” in-process
3,224,816
0.00031
3,277,973
0.00031
"Alpha™," in-process
2,801,630
0.00036
2,834,269
0.00035
"Pentium," cross-process
2,377
0.42
2,023
0.49
"Alpha," cross-process
1,925
0.52
1634
0.61
"Alpha," to Pentium remote
376
2.7
306
3.27
开始两列表示一个“空”方法调用(发送和接收一个4字节长的整数)。最后两列可以认为是一个“真正的”COM方法调用(50字节长的参数)。
此表显示了进程中组件是怎样得到零开支的执行性能的(第一排和第二排)。
进程之间的方法调用(第三排和第四排)需要将参数存入缓冲器并将其发送给其它的进程。在一个标准的桌面办公系统硬件中,每秒钟大约可以执行2000个方法调用,这可以满足大多数的执行性能需求。所有的本地调用是完全由处理器速度(一定程度上由存储器容量)决定的,并且能够很好地适用于多处理器型机器。
远程调用(第五排和第六排)主要受限于网络速度,同时可以看出DCOM的开支大约比TCP/IP多了35%(TCP/IP的循环时间是两秒)。
微软很快会提供许多平台上的正式的DCOM性能参数,它将显示出DCOM与客户数量以及服务器中处理器数量相关的扩展能力。
带宽及潜在问题
分布式应用利用了网络的优点将组件结合到一起。理论上来说,DCOM将组件在不同的机器上运行这一事实隐藏起来。实际上,应用必须考虑到网络连接带来的两个主要限制:
带宽:传递给方法调用的参数的大小直接影响着完成方法调用的时间。
潜在问题:物理距离以及相关的网络器件(例如路由器合传输线)甚至能使最小的数据包都被显著地延迟。
DCOM怎样帮助应用解决这些局限呢?DCOM自己将网络循环时间最小化,使得避免网络中潜在的拥塞成为可能。DCOM选择了TCP/IP协议套件中的无连接UDP协议作为自己的传输协议。协议的无连接特性使得DCOM能够将许多低级别的确认包和实际的数据以及地址合法性检查(pinging)信息混合起来从而改善了性能。即使是运行在面向连接的协议上,DCOM也优于传统的面向特殊应用的协议。
在应用间共享连接管理
大多数的应用级别的协议需要某种从头到尾地管理。当客户机出现了严重的硬件故障或者客户和组件之间的网络连接中断已经操过一定时间时,应该及时通知组件。
解决这一问题的一个普遍方法是个一段时间(Pinging)发送保持活跃keep-alive消息。如果服务器在一定的时间间隔内没有收到一条ping消息,它就断定客户进程“死掉了”。
DCOM对每台机器使用一个keep-alive消息。即使一台客户机使用了某一台服务器上的100个组件,仅仅只要一条ping消息就能使所有这些客户连接保持活跃状态。为了将所有的ping消息组合起来,DCOM使用delta pinging机制来将这些ping消息的大小最小化。对于这100个连接,它并不是发送100个客户标识符,而是创造了一个可变标识符来重复代表这100个引用。当引用集改变时,仅仅只是两套引用的相交的部分被互相交换。最终,DCOM将所有ping消息转化为正常消息。只有当对于服务器来说,某台客户机完全是空闲的时,它才定时发送ping消息(每隔两分钟一次)。
图9 组合的生命期管理
DCOM允许多个应用(甚至来自不同的卖主)共享一个简单而且优化的生命期管理和网络错误检测协议,这样可以显著地减少带宽。如果在一台服务器上运行使用100个不同的传统协议的100个不同的应用,对于每一个客户连接上的每一个应用来说,服务器都要接收一条ping消息。只有这些协议当在它们的pinging策略上相互合作时,整个网络的开销才有可能减少。而DCOM在任意的基于DCOM的协议中自动地提供了这种协作。
优化网络的来回旋程
设计分布式应用的一个普遍问题是减少不同机器上组件之间在网络上的过度的来回绕圈数。在Internet上,每一次网络绕圈就会引入1秒甚至更多的延迟。即使在速度快的局域网上,旋程时间也是以微秒来计算的──它超过了本地操作所需时间的量级。
减少网络绕圈数的一个普遍的方法是将多个方法调用捆绑起来。DCOM将这种技术扩展使用,用来解决诸如连接一个对象或者创造一个对象查询对象的机能的任务中。这种技术对于一般组件的不足之处是它在本地和远程情况下的编程模型差别太大。
例子:一个数据库组件提供了一个能够分行或多行显示结果的方法。在本地的情况下,开发者只需使用这个方法将结果一列一列地加入列表框即可。而在远程的情况下,每列出一行就会引起一定的网络旋程。使用批量方式的方法需要开发者分配一个能容纳查询出的所有列的缓冲器,然后在一次调用将其取回并将其一列一列地加入到列表框中。因为编程模型变化很大,开发者需要对设计作大的改动以便应用能够在分布式环境中有效地工作。
DCOM使得组件开发者能够轻易地执行批量技术而无需客户端也使用批量形式的API。DCOM的marshling机制使得组件可以将代码加到客户端,这叫作“代理对象”,它可以拦截多个方法调用并将其捆绑到一个远程调用中去。
例子:因为应用系统的逻辑结构的需要(列表框API的要求),上面例子的开发者仍然需要一个一个地列举方法。然而,为了列举查询结果的第一次调用应用中特殊的代理对象,它取得了所有列(或者一批列)并将其缓存到代理对象中。后来的调用就自接从这个缓存中发出,就避免了网络旋程。开发者仍然使用一个简单的编程模型,而整个应用却得到了优化。
图10组件模型:客户端的缓存
DCOM同样允许从一个组件到另一个组件的有效的指引。如果一个组件保存了到另一台机器上的一个组件的索引,它可以将其传递给在第三方机器上运行的一个客户进程(假设此客户进程正在使用另一台机器上运行的另一个组件)。客户进程使用此索引就可以直接和第二个组件通讯。DCOM缩短了这种索引,并且使得第一个组件和机器可以完全从这个过程中脱离出来。这使得能够提供索引的传统的目录服务适用于远程组件的范围。
例1:一个棋类应用系统能够使正在等待对手的用户将自己登录到一个棋类目录服务中。其它的用户可以浏览并查询正在等待对手的用户的列表。当一个用户选择了自己的对手后,棋类目录服务系统将对手的客户组件索引返回给该用户。DCOM自动连接两个用户,目录服务系统无需涉及任何其它的事务处理过程。
例2:一个“经纪人”组件监控着运行着同一个组件的二十台服务器,它监测服务器的负载量和服务器的加入和删除情况。当一个客户需要使用该组件时,它连接到“经纪人”组件,此组件返回负载最轻的服务器上的一个组件的索引。DCOM自动连接客户和服务器,此时“经纪人”组件和以后的过程就无关了。
图11索引指示
如果需要的话,DCOM甚至允许将组件插入任意一个传统的协议中,这个协议可以使用不在DCOM机能范围内的方法。组件可以使用传统的配置方法将任意的代理对象放到客户进程中,此进程能够使用任何协议将信息传回组件。
例1:一个服务器端组件可以使用一个ODBC连接来和一个SQL Server数据库通讯。当客户取得对象后,客户机直接和SQL Server数据库(使用ODBC)比使用DCOM和服务器通讯,同时服务器和SQL Server数据库通讯更有效。在DCOM的传统配置情况下,数据库组件能够将自己复制到客户机上,并将自己同SQL Server相连接,而此时客户并没有意识到自己已经不再和服务器上的数据库组件相连了,而是和该组件的一个本地复本连接这着。
例2:一个商业系统需要两种通讯机制,一种是从客户端到中央系统的一条安全而经过鉴定的通道,它用来发出和撤消命令;另一种是一条分布式的通道,它用来将命令信息同时发送给连接在系统上的客户。使用DCOM的安全而同步的连接方式可以简单而有效地操作客户机/服务器之间的通道,同时广播通道需要一种更为尖端的机制,它使用多点广播技术以便容纳大量的侦听者。DCOM允许将传统的协议(“可靠的广播协议”)无缝地插入到应用系统的体系结构中:一个数据接收端组件能够将此协议封装起来,并使其对客户和服务器完全透明。当用户数量少安装量小时,标准的DCOM点到点协议就足够了;而对于有很多用户的站点来说,就需要使用高级的广播协议。DCOM将来会提供一个标准的多通道广播传输协议,它能够无缝地移植到应用系统中。
图12 用custom协议代替DCOM
安全性
使用网络来将应用系统分布化是一个挑战,这不仅是因为带宽的物理限制以及一些潜在的问题,而且也由于它产生一些诸如关系到客户间、组件间以及客户和组件之间的安全问题。因为现在的许多操作可以被网络中的任何一个人访问,所以对这些操作的访问应该被限制在一个高级别上。
如果分布式开发平台没有提供安全支持,那么每一个分布式应用就必需完成自己的安全机制。一种典型的方法是用某种登录的方法要求用户通过用户名及密码的检测,这些一般来说都是被加密了的。应用系统将通过用户数据库或者有关目录来确认以上用户身分,并返回动态的标识符以便用户以后用来进行方法调用。以后每次涉及到调用有安全检查的方法时,用户都需要通过这种安全认证。每个应用系统都要存储和管理许多用户名和密码,防止用户进行未授权的访问,管理密码的改动以及处理在网络上传递密码而带来的危险。
因此分布式平台必需提供一个安全性框架来确切地区分不同的用户或者不同组的用户以便系统或应用有办法知道谁将对某组件进行操作。DCOM使用了Windows NT提供的扩展的安全框架。Windows NT提供了一套稳固的内建式安全模块,它用来提供从传统的信用领域的安全模式到非集中管理模式的复杂的身份确认和鉴定机制,极大地扩展了公钥式安全机制。安全性框架的中心部分是一个用户目录,它存储着用来确认用户凭据(用户名、密码、公钥)的必要信息。大多数并非基于Windows NT平台的系统提供了相似或相同的扩展机制,我们可以使用这种机制而不用管此平台上用的是哪种安全模块。大多数DCOM的UNIX版本提供了同Windows NT平台相容的安全模块。
安全性设置
DCOM无需在客户端和组件上进行任何专门为安全性而做的编码和设计工作就可以为分布式应用系统提供安全性保障。就象DCOM编程模型屏蔽了组件的位置一样,它也屏蔽了组件的安全性需求。在无需考虑安全性的单机环境下工作的二进制代码能够在分布式环境下以一种安全的方式工作。
DCOM通过让开发者和管理员为每个组件设置安全性环境而使安全性透明。就象Windows NT允许管理员为文件和目录设置访问控制列表(ACLs)一样,DCOM将组件的访问控制列表存储起来。这些列表清楚地指出了哪些用户或用户组有权访问某一类的组件。使用DCOM的设置工具(DCOMCNFG)或者在编程中使用Windows NT的registry以及Win32的安全函数可以很简单地设置这些列表。
只要一个客户进程调用一个方法或者创建某个组件的实例,DCOM就可以获得使用当前进程(实际上是当前正在执行的线程)的用户的当前用户名。Windows NT确保这个用户的凭据是可靠的,然后DCOM将用户名正在运行组件的机器或进程。然后组件上的DCOM用自己设置的鉴定机制再一次检查用户名,并在访问控制列表中查找组件(实际上是查找包含此组件的进程中运行的第一个组件)。如果此列表中不包括此用户(既不是直接在此表中又不是某用户组的一员),DCOM就在组件被激活前拒绝此次调用。这种安全性机制对用户和组件都完全是透