影响分布式对象系统的性能和扩展性的关键因素是“能否控制server端所持有的分布式对象的个数”(0分)

  • 主题发起人 主题发起人 zzsczz
  • 开始时间 开始时间
Z

zzsczz

Unregistered / Unconfirmed
GUEST, unregistred user!
影响分布式对象系统的性能和扩展性的关键因素是“能否控制server端所持有的分布式对象的个数”
几个术语的解释
组件对象模型:开发oo软件所遵守的规范(从开发class的programer这一方来看)
com:微软的一种组件对象模型。
微软还有一种组件对象模型,是.net。
组件对象模型的支持环境:为对象提供服务的系统级软件。
com作为组件对象模型,它的支持环境有4代:
第1代 ole,ole2
第2代 dcom
第3代 mts
第4代 com+(com plus)
注意,com plus这种支持环境也可以对.net这种组件对象模型的对象实例提供系统服务。
(也可以 说.net 的某些组件可以调用com plus的服务)
.net将淘汰com(component object model)这种组件对象模型。
但说.net将淘汰com plus是完全错误的说法,两者是有联系,但是不具备可比性。

历史
windows的单机时代,即是ole和ole2时代,当时的组件对象模型的支持环境提供的功能集中在使“遵守com的组件实现二进制代码的重用”。使用组件的programmer只用关心“得到一个功能(即接口)”,不用关心功能由哪个组件供,以及功能如何实现。

dcom作为组件对象模型的支持环境,提供的功能有限。dcom只能做到“使用组件的programmer只用关心得到一个功能,不用关心功能由哪个机器上的哪个组件供提供”。这种做法可以让熟悉ole/ole2的programmer重用以前的经验,快速掌握dcom环境。

如果用基于ole/dcom的经验开发分布式应用,问题也随之而来。
影响分布式对象系统的性能和扩展性的关键因素是“为对象提供服务的系统级软件能否控制server端所持有的分布式对象的个数”
因为有的对象占用大量的资源(内存,cpu,数据库连接),如果这种对象数量太多,服务器的效率急速下降(原因有:事物冲突,死锁,大量的线程切换,以及死掉的client没有释放资源)。服务器最终将被拖垮。想像一下:1000个client,每个client请求5个包含数据库连接 的对象的接口,那么dcom将建立5000个数据库连接,服务器绝对死翘翘。
我把这种对象称为“重型对象”
在分布式系统中,programmer应该关心和理解对象(特别是“重型对象”
)是如何被“实例化”(intstantiation)的。在单机时代,这种需求不是那么迫切。但是在在分布式系统中,仅仅关心使用接口是不够的(原因如前所讲)。
但是,微软把com的接口当作噱头说事,淡化“对象”的概念,因为没有一种编程语言从语法上直接支持com的对象(idl可能算,但是idl知识只是起到辅助c++的作用。各种面向对象语言构造对象的方式是扎根在语法中,不能“跨语言”。必须用factory 模式把实现“构造”的语义)。
dcom的陷阱。
如果用dcom开发多层应用,那么使用接口的programmer在远程机器(既是服务器)上建立重型对象的实例的方法是有讲究的。
影响“dcom如何建立一个对象(在哪个进程中?需要新建立进程吗?在哪个线程中?需要新建立线程吗?)来响应client的请求”的因素有这么几个:1对象的intstantiation属性,2对象的线程模型(sta,mta,boath),3类厂(类对象或class factory,都是一个说法)的设计方法。
解释:
对象的intstantiation属性:
dcom环境中的对象都是属于某个进程的。
如果说一个进程只能容纳某个对象的一个实例,那么这个对象的intstantiation属性被称为“single instantiate”
如果说一个进程只能容纳某个对象的多个实例,那么这个对象的intstantiation属性被称为“multiple instantiate”

当client向dcom请求一种接口时 ,dcom发生的事情如下:
if(dcom发现此次请求的是该种接口的第一次请求){
dcom将启动第一个进程xxx,在此进程中制造一个支持该接口的对象,把该对象up cast(类型塑造,转型)成接口,传(marshal,列集)给client。}
else
{
if(支持该接口的对象的intstantiation属性被称为“single instantiate”){
dcom将另外启动第一个进程yyy,在此进程中“制造”一个支持该接口的对象,把该对象up cast(类型塑造,转型)成接口,传(marshal,列集)给client}
else
if(支持该接口的对象的intstantiation属性被称为“multiple instantiate”){
dcom将在进程xxx中再次“制造”一个支持该接口的对象,把该对象up cast 成接口,传(marshal,列集)给client}

基本上是这个样子。注意“制造”的方法存在于class factory中。各种framework(vc的atl,delphi 的vcl)各自的都设计了classfactory的实现方式。基本上,client每次请求一个接口,一个对象就会被实例化。client无法指定接口邦定于哪个对象的实例。而“重型对象”
对于这种classfactory默认的“制造”方法是不能容忍的。

接口的线程模型
这个概念实在是个鸡肋。不了解吧不行。因为它是com的专有概念,而且微软把它当作噱头。(作为分布式对象的使用者不应该了解这种多余的底层的琐碎的概念)。想了解,几句话又说不清,搞懂了用处又不大。
线程模型标识了com对象和client两者的线程相容性。如果client的线程模型和com对象的接口的线程模型不相容,那么com的支持环境就会调整client和com对象的接口之间的“交流”。

搞懂了用处又不大。因为多数人都使用atl或vcl开发com对象,这些framework中的设计好 的classfactory隐藏了所有细节,其中包括线程模型的差异如何影响对象的建立。对象的建立方式的差异会影响对象的表现。而在不同framework 中的classfactory中,具有相同的线程模型标识的接口,其对象的建立方式没有规定(甚至同一个framework的不同版本,对具有某种线程模型的接口的对象 有不同的建立方式)。于是线程模型对com对象的影响就非常微妙。
举个极端的例子:delphi4和delphi5中建立dcom 对象,要求intstantiation属性被称为“multiple instantiate”,线程模型为“sta”(单套间线程模型,或 single thread apartment model,都是一个意思)

d4 的classfactory是这么干的:dcom在第一个进程xxx中的主线程中直接create一个对象,把该对象up cast(类型塑造,转型)成接口,传(marshal,列集)给client。

d5中classfactory是这么干的:dcom在第一个进程xxx中新建立一个线程,标识为sta 线程,在该线程中 create一个对象, 把该对象up cast(类型塑造,转型)成接口,传(marshal,列集)给client。

当多个client请求d4 版本的接口时,所有的com对象都在进程xxx的一个sta线程中。所有client对各自接口的调用被sta线程的message loop同步。也就是说一个client的调用会被其他client阻塞。而当多个client请求d5 版本的接口时,所有的com对象都在进程xxx都有各自的sta线程。一个client对自己接口的调用和其他client没有关系。

intstantiation属性决定一个对象在哪个进程中被实例化。而线程模型决定了client如何与com对象交流。dcom没有提到“控制server端所持有的分布式对象的个数”。

解决方法:
“控制server端所持有的分布式对象的个数”就成了dcom组件编写人员自己要操心的事情。
delphi的sample/midas/pooler目录中有一个例子。它提供了dcom环境下client之间如何“共享”对象的实例的一个方法。(说具体点:多个client如何共享数量有限的数据库连接)

当client向dcom请求一个接口时,dcom就实例化一个对象(类型为a)。每个client都有 各自的”a对象”的实例。“a对象”的intstantiation属性是“multiple instantiate”,于是所有client的“a对象”的实例都在相同的进程xxx中。同一个进程有一个heap区域,各个“a对象”的实例都可以访问这个heap区域,各个“a对象”的实例还可以访问进程xxx中中的全局变量。当client通过接口向“a对象”发消息时(就是调用接口中的函数),“a对象”自己自己什么都不做,只“传话”,把消息发给heap中的空闲的b对象”的实例。“b对象”是“重型对象”,包含数据库连接。“b对象”的实例个数可以在进程xxx的初始化过程中指定。这样就控制了服务器上“重型对象”的个数。如果heap中没有空闲的“b对象”(都在工作中,个数达到上限),那么“a对象”将等待,直到找到可用 的“b对象”,这个过程中,client也在等待。

大致上就是这个样子。其他细节方面:1 “b对象”的实例放在链表中管理。 2“b对象”的方法要用critical sectiom(临界区域)保护。3“a对象”必须是无状态的。
这个例子还不完善,服务器不能识别“死掉”的client所占用的资源。长时间运行后,所有 的“b对象”可能都会处于“busy”状态,被“死掉”的client所占用 。系统就不能正常工作了。要想把这个例子实用化,还要加很多代码。

这是borland的做法 。微软也有相似的方法,sql server的ado驱动自带pooler功能,原理也差不多(驱动编写人员辛苦了。如果驱动不带pooler功能 ,使用人员就辛苦了 )。

dcom结论
dcom没有提到“控制server端所持有的分布式对象的个数”。要做到这个功能,编写 组件的programmer自己必须处理很多细节。设计一个“重型对象”,用dcom实现时,必须写2个class,一个代理(指逻辑功能代理,即a对象,不是指dcom中的proxy和stub),一个实现(b对象),还要注意保护代理和实现之间的交流,并防止资源泄露。用dcom实现“重型对象”是非常烦琐的。

complus的进化:控制server端所持有的分布式对象的个数
complus提供的服务要比dcom的多。重点在:pooler和jita(just in time activate)。jita可以把对象的实例化从client请求接口的时刻延迟到client向对象发消息的时刻,节省了内存。com plus的内置的pooler功能,指定对象的个数的上限,简化了开发,提高了可靠性。在complus 环境中,client可以直接通过cocreateinstence请求一个“重型对象”的接口,并查看返回值,看看是超时还是成功。只用设计业务对象(“对象b”),不用管细节(“对象a”,同步,资源管理等等),比dcom轻松 许多。


midas的发展:
midas的最初功能是为不完善的windows(不完善的dcom)提供分布式服务,
随着com plus的完善,midas的作用降低,变成语言中立的数据打包协议。

java的发展
java的rmi(remote methord invoke)提供了和dcom相似的功能。
而java的ejb规范提供了和com plus相似的服务(可以控制server端所持有的分布式对象的个数
).把组件放在container中,指定container的属性:对象个数上限,超时时间,等等。




 

更重要的是:java平台只有一种主流语言:java,可以很方便的实现object-relation mapping技术,提高开发效率,(比如cmp,jdo,cocobase,toplink,hibernate,castor,最后两种还是免费的)。
com为了垮语言,在OR mapping方面毫无进展。com plus没有为object-relation mapping提供任何服务。
 
感觉好像没完,呵呵,还有吗?
学习。
 
后退
顶部