上一篇:互联网走向架构web2.0和应用个人门户化 >>
头脑风暴 “攒”出更稳定的软件
本文提出了一种极具启发性的程序运行时结构,将一个完整的单体程序划分为若干运行在独立地址空间的子进程,并以一个监管程序进行调度,从而大大提高了整体程序的强健性。文章依托成功的实践经验,提出的原理具有普遍适用性,非常具有参考价值。
一、问题来源
目前触摸屏已经得到广泛的使用,相信绝大多数的读者都曾经接触过,比如在邮局用于查询邮政编码、在药店用于检索药品的性能和价格、在学校门口用于学校的简单介绍、在电脑城用手查询其产品信息等。尽管这种触摸系统随处可见,但是我们更常见的现象就是如果你在某处看到曾经正常运行的这种系统,之后不久往往会看到类似于“本系统暂停使用”之类的信息,或者干脆没有任何提示但是机器已经被关闭。如果你曾经留意过这种现象,你想过其原因吗?
根本原因在于这些系统往往不能稳定地运行。某个部门或单位在决定使用触摸系统时往往注重其方便、友好的界面,但是由于种种原因却根本未考虑或者有意忽略(“有意忽略”的原因读者可以自己琢磨)了这种系统与普通应用程序的对稳定性要求的区别。对于一个普通的运行于PC机上的软件,即使其不正常退出也没有太多问题,因为用户可以重新执行。笔者使用的某著名杀毒软件曾多次在杀毒的过程中不正常退出。但是触摸系统则在以下几方面表现出很大不同:一、可能根本无人职守,因此出现故障时,系统就会停止运转;二、即使有人职守,职守人员也往往是非专业人员;三、触摸系统供大众使用,程序退出后会暴露操作系统,会被恶意破坏。对于那些按照普通应用程序思路设计的系统(往往用VB开发),在频繁出现稳定性问题的时候,用户刚开始时还能够忍受,但是时间长了,工作人员往往变得烦不胜烦,这时往往就是“本系统暂停使用”的时间到了。笔者曾亲眼目睹韩国某上市公司的这种软件在软件博览会上展示时软件出现错误而不正常退出的场景,你能想象在场的其公司董事长(也是软件的主要开发者)的尴尬状况吗。
这种情况就要求我们必须设计一种具备高稳定性的系统来保证系统的正常运行。
二、新结构的设计
我们首先可以想到的就是,将程序分割。任何人都可以理解,一个1M大小的程序出错误的概率要远远大于一个50K的程序,因此如果我们将一个1M的程序拆分为若干个50K的独立程序,那么整个系统其出错的概率就会大大降低。这就是在文章开始时所演示的执行一个“任务”而在任务管理器中却出现4个任务的原因,这也是我们要对“任务”使用引号的原因,因为这是一个泛义的“任务”,需要与Windows的任务管理器所认为的任务相区分。
将任务拆分可以提高系统的稳定性,但是整个任务仍然必须是一个有机的整体(为叙述方便,以后将整个程序称为任务,而将各个拆分的程序称为部件),因此就需要在各个部件之间定义一个接口,通过这种接口将各个部件有机的联系为一个整体,就好象通过各种标准的接口将键盘、鼠标、显示器等部件有机地结合为一台PC机一样。
严格地讲,简单地将任务拆分为多个部件对提高系统的稳定性只有有限的作用,因为在未拆分的情况下,发生错误的代码将导致整个任务的结束,而在拆分之后则只是导致错误代码所在部件的退出,这似乎提高了系统的稳定性,但是缺少某些部件的任务实际上根本不能算是一个完整的任务,因此紧跟而来的就是程序的纠错机制即自我修复机制的建立。因为只有在任务保证完整性(对出现错误的程序具有自我修复)的情况之下,才可以真正地说程序的稳定性得到了提高。 现在让我们设想一下,如果PC机的键盘坏了,我们怎么办?我们当然是去买一个新的键盘来替换它。那么当组成任务的某个部件因出现错误而退出,那由谁去“买”个新的部件去替换它呢?因此很显然我们需要一个类似于PC机的使用者(人)的角色出现于程序中,我们称其为调度者,因为人实际上是整个PC机的使用和维护者,关于调度者的概念通过后面的说明会变得更为清晰。当任务需要使用某个部件的功能时,它首先检查该部件是否能够正常使用,如果不能使用,那调度者就会自动去“买”个新的部件替换原来的部件从而保证程序的正常运行。 当然很少出现(但是并不等于不出现)的情况就是调度者本身出现了错误(因为调度者的程序一般非常小,因此其出错的概率很低,但是在实际运行中笔者也的确发现过调度者出现错误的现象),也就是监管者本身出现了“腐败”,谁去监管监管者呢?为此,在任务中又引入了一个对调度者进行监控的程序,一旦发现调度者出现错误,则可以采用类似调度者修复部件的方式对调度者进行修复。可以想到的是,调度者的监控程序更小,其出错误的概率更低。当然为了进一步提高系统的稳定性,可以设置多级这样的监管程序。
通过前面的叙述,可以清楚地看出,这种新的架构可以极大地提高程序的稳定性,因为:1、将任务拆分为部件降低了程序发生错误的概率;2、调度者的出现更增加了系统的自我纠错机制,保证了部件的正常;3、监控程序更从整体上保证了系统的“健康”。
通过这样一套机制的建立,虽然从理论上,任务仍然可能出现错误,但是经过实践验证,实际上出现错误的现象几乎很难遇到。实际上其稳定性即使不经过验证也是可以设想的。
基于这种设计思想,笔者开发了运行于公众场合的软件。这种软件在公众场合、不关机情况下连续数月累年的运行就充分证明了这种结构的稳定性。这种结构可以称为小程序拼凑大程序的设计方法(所谓“攒软件”),实现了公众场合软件“稳定压倒一切”的要求。其最典型的应用是,某个项目为了达到美观、摄人心魄的境界,所有资料均为多媒体文件(Flash/MEPG/AVI/WAV等),资料文件达到800M之多,其工作人员深知其对稳定性的要求,在对多家软件进行长时间的考察之后,与笔者进行了一个多小时的谈话,获悉该结构后,立即决定使用该软件。经过实践,本软件在24小时连续运行的情况下,实现了系统的稳定运行。
三、调度者的由来及其作用
前面我们讲到,调度者其实是模拟PC机的使用者的作用。但是实际上调度者除了完成部件的监控与修复的功能之外,还充当了整个系统的指挥、协调者的角色。就好象舞台上的导演一样。在舞台上,导演按照剧本的要求,指挥各个演员在不同的场景完成规定的动作。调度者也是如此,它按照软件流程的需要,调度各个部件,这也这是调度者这一名字的来源。
调度者和部件之间需要完成双向通信,调度者与部件之间的通讯方式有很多种,通过对象的属性、方法等均可。而部件向调度者反馈信息的方式则有以下两种:
1、事件
2、直接通讯
其中通过事件方式是向不确定的调度者反馈,而直接通信则向特定的调度者反馈。
原则上部件只和调度者发生关系,即调度者向部件下达各种命令,而部件向调度者反馈各种事件,部件之间除非特别需要原则上不直接发生关系。以避免形成网状结构而使得整个程序变得混乱不堪。
四、结构的优缺点
这种结构具有以下优点:
1、具有高度的稳定性。该结构具有从体制上防止“腐败”的优点,这是其首要的优点。
2、结构清晰。因为各个部件各司其职,由调度者统一协调各个部件,因此只要将调度者和部件之间的接口定义清晰即可,整个结构清晰。
3、可以同时多人并行开发。每个开发人员只要完成自己负责的部件即可,相互之间互不相干,因此可以并行工作,并且在工期紧张时可以随时增加人手,而不会对整个系统有什么影响。
4、方便定制。可以根据客户需要很快生成相应的软件。
5、部件Wizard可以加快开发速度。对于部件尽量定义统一的接口(关于接口的定义,后面会专门叙述)。这样就可以生成部件Wizard, 然后只需要增加相应的功能即可。
6、个人因素对整个系统影响有限。如果某人因为某种原因开发的部件不理想,可以另外开发一个即可。就好象某种鼠标使用效果不理想,换另外一个鼠标即可。
该结构缺点如下:
整个系统的性能有些下降。关于性能的问题,后面会专门介绍。
五、实现技术的讨论
在所提供的演示程序中,整个系统是以VB实现的。监控程序、调度者以及2个部件均是用VB编程实现的,在VB中最简单的实现方式就是以ActiveX程序的形式实现各个部件和调度者。整个演示程序以调度者的监控程序为起点,它创建调度者,而后调度者创建各个部件,调度者
的监控程序不断探测调度者是否正常,不正常则恢复之,而调度者检测各个必须的部件是否出现故障的方式有两种:1、定时检测;2、按需检测(即在需要使用某个部件时首先检测其是否正常,不正常则恢复之)。在演示程序中,检测者与被检测者之间是通过ActiveX程序的方法实现的。
尽管如此,但是该结构的核心是拆分和监控,是程序之间的通信,因此任何实现进程间通信的技术,比如进程同步机制等,都可以用来实现该结构。读者可根据不同的情况自由选择,我们需要遵循的只是这种提高稳定性的结构。具体到演示程序,因为调度者、部件均选择为ActiveXEXE,因此需要对部件进行必要的注册,在演示程序中,我们提供了一个程序用于完成这种注册。但在实际开发中,注册的操作应当由安装程序完成。
六、VB 实现中的问题
在程序员杂志2004年第10期《掌握汇编依然是技术高手的必经之路》的访谈中,在谈到汇编语言的发现bug的能力时,我曾经谈到以下的一段话:“曾经用VB编写一个程序,该程序通过创建对象与另一个程序通信,但是VB在将对象变量与原来的对象切断联系之前,不允许同一个对象变量重新创建对象,这种处理方式无所谓对错,但是我们的工作却要求如此,因此通过对VB 的msvbvm50.dll(msvbvm60.dll)的跟踪修改,使VB的工作机制符合我们的要求。”..
这段话中所描述的问题就是实现这种结构时所遇到的。通过演示就可以发现,部件程序是由调度者创建的,而当调度者发现某个部件存在故障时,就会重新创建该部件,但是VB5/VB6对于这种情况的处理均是无法重新创建部件,为此笔者对msvbvm50.dll/msvbvm60.dll进行跟踪修改了VB的这种处理机制,从而使自动恢复成为可能。必须说明的是,这种问题的出现是由VB的处理机制造成的,用其它环境实现未必会出现此问题。
以下是我在1999年所写的关于修改VB5.0/6.0的DLL文件MSVBVM50.DLL/MSVBVM60.DLL的说明:
1 为什么要修改该文件?
VB的Set ObVar = nothing和Set ObVar = CreateObecjt(...)语句在很多情况下执行失败,并且会返回错误信息:自动化错误。经过对VB的分析发现,VB在将一个Object变量与一个新的对象建立连接之前必须与原来的对象切断联系,这样如果原来的对象因为某种原因不能工作(不响应--比如程序down),则这种语句就不能切断与原来对象的联系,从而也就不与新的对象建立联系,并返回“自动化错误”信息。VB的这种处理方法固然有其道理,但是在实际应用中,这种处理方法常常导致新对象无法创建,因此有必要修改其处理方式。
2 修改方法
我们知道,VB的核心文件为MSVBVMX0.DLL,其中提供了大量的函数,而与我们的问题的相关联的函数为MemSetEvent,该函数负责检查对象变量的有效性,并负责切断与原来对象的联系,其方法是:检查对象变量是否有原先发生联系的对象,如果有,则调用相应对象的清除过程。
因此如果原来的对象已经down掉,则该过程无法实现,因此VB返回"自动化错误"信息。如果我们能够将让该函数永远认为不存在原来的对象,则该过程保证永远成功。
3 修改过程(以VB5为例,VB6与此类似)
在MSVBVM50.DLL中查找以下代码序列,并按照以下方法修改即可:
| 原始代码序列 修改为 56 push esi 8b 06 mov eax,[esi] ff 50 04 call [eax+4] 8b 45 08 mov eax,[ebp+8] 8b 38 mov edi,[eax] 33 ff xor edi,edi 83 c0 04 add eax,4 89 45 f4 mov [ebp-0c],eax 85 ff test edi,edi |
保存文件即可。
特别说明:在调试环境中,该功能是无效的,因为调试环境未使用msvbvm50.dll,而是建立了一个模拟环境!
需要说明的是,在调试演示代码的时候,所使用的操作系统为Windows XP Professional,其msvbvm60.dll的日期为2003年1月24日。虽然没有对msvbvm60.dll进行修改,但是似乎可以进行恢复,是否是msvbvm60.dll修改了其原来的处理方式、Windows 2000的svbvm60.dll是否如此还需要验证。
但是不论如何,对于早期的VB其问题存在,在此说明这种修改方法,如果读者在实验时遇到无法恢复的情况,可以参考进行修改。
七、性能问题
我们知道,进程通信会降低程序的性能。在最初设计该结构时,为了检验这种结构究竟会对系统的性能造成何种影响,曾经将一个近万行的VB程序拆分大约20个程序进行试验。当时所采用的系统配置如下:CPU——奔腾200, 内存——64M,虽然没有采集对性能影响的具体数
据,但是经过验证系统性能是完全可以接受的。在当今, 无论CPU、内存,还是硬盘的性能与当时的实验环境完全不可同日而语,因此这种结构对性能的影响几乎可以不需要考虑。当然读者如果有兴趣,可以对该结构性能的影响进行实验,如果有具体的数据结果,欢迎告诉笔者。在此先表示感谢。
八、接口的设计、扩展
实现调度者与部件之间的通信是该结构的基本要求,调度者与部件之间的接口方式有很多种,常见的就是属性、方法和事件、进程同步机制等。但是因为每种部件功能不一,需要设计许多不同的结构,这就给设计带来了麻烦。就好象在PC机中,各种不同的设备与系统有不同的接口,导致出现大量不同的接口,为设计带来困难。其实完全可以设计统一的接口,在PC中也出现这种趋势,比如USB的出现。请注意USB的全称为“Universal Serial Bus”,其中的Universal就是“通用的”,“一致的”的含义。在该结构中,通过实现统一的接口,既简化设计而又便以实现脚本化。但限于篇幅,在此不再赘述。
虽然该结构一开始是为了解决触摸系统的对稳定性的要求而设计的,但是实际上这是一种通用的软件结构。一个企业可以开发大量的这种部件,然后以支持脚本的方式实现一个编辑环境,就可以随意生成各种程序。感兴趣的读者可以自行实现。
九、关于演示程序的说明
最后,简单对演示程序进行解释如下:
1、执行register.exe,该程序完成两个部件、调度者的注册,因为它们是ActiveX 程序;
2、执行monitor.exe。该程序启动调度者,然后调度者启动部件1、部件2,系统进入正常运行状态;
3、按部件1上的Crash(腐败)按扭,会导致部件1关闭,观察会发生什么;
4、按部件1上的“切换”按扭,切换到部件2的界面;
5、按部件2上的Crash(腐败)按扭,会导致部件2关闭,观察会发生什么;
6、按屏幕右上角的“Crash”按扭会导致调度者关闭,观察会发生什么;
7、监控程序没有设置退出方式,因此要结束整个系统,必须用任务管理器之类的工具进行关闭,关闭次序如下:
(1)杀掉monitor.exe进程
(2)杀掉dispatcher.exe进程
(3)杀掉comp1exe和comp2.exe进程
请注意,必须按照此顺序进行,否则你会发现很难关闭整个系统,因为会不断地进行自动恢复。你也可以如此尝试以增加对该结构的认识。
下一篇:Web程序员年薪10万 本科生起薪3.8万 >>
相关文章:
- · 怎样处理Java最终化的内存保留问题
- · Java规则引擎与其API应用详解
- · 14岁博客发现Gmail可以执行Javascript
- · MSN再次大面积瘫痪 微软称尚未查明原因
- · MSN登录问题集中在7.5版本 升级到8.0即可
- · MSN与雅虎通互通整合已进入内测阶段(图)
- · MSN遭遇陌生人入侵风波 网友怀疑信息被泄露
- · MSN白领化的精明和无奈
- · 提高IE以及Email安全性的四大步骤
- · 警告:搜索用户,你可能彻底被暴露了
- · 网上惊现超强恶意程序 安全卫士升级查杀
- · 一招搞定nb46.com这个超级流氓
- · 看看上网助手背后的“故事”
- · 雅虎助手恶意干扰超级兔子清理王运行
- · 安全清晰互联互通 Vista主要特性揭密
- · Skype否认软件遭破解 称克隆软件缺乏安全
- · 赛门铁克称Vista不如XP安全微软是白费努力
- · Windows Vista中Photostory将逐渐消失
- · Vista 5472仍未改变Windows 3.1对话框
- · 深入体验Windows Vista 5472新特性
- · 解析Vista与系统不协调的三大工具界面
- · Win Vista新功能介绍之网络映射的使用
- · 小编谈近期工具软件
- · 没有什么不可以 电脑和软件也来共产主义
- · PS数码暗房:将蓝天白云变成黄昏夕阳
- · 盖茨刚退休微软高管闪电离职 为鲍尔默心腹
- · 徐静蕾要跑啦!利益驱动 名人博客自立门户
- · 敏思博客将关闭 危机能否代表web2.0
- · 后盖茨时代来临 软件巨人大胆扶植新领袖
- · photoshop滤镜打造绚彩水晶花朵
- · 为不同设计需求选择合适的photoshop滤镜
- · 盖茨离开后:微软还是微软
- · vizros外挂滤镜轻松实现画面卷曲特效
- · 网页篡改猖獗,防篡改战争进行时
- · 用photoshop滤镜模拟毛笔笔触特效
- · 微软推出Live Messenger 实施网络服务战略
- · 体验新服务 google notebook 试用报告
- · Live不满足仅仅进驻浏览器 将登陆Windows
