一、前言

随着互联网的发展以及电子商务应用的兴起,多层分布式系统的开发和应用已成为企业和开发者关注的焦点之一。在一个执行关键作业的多层应用系统中,系统的稳定性是非常重要的,尤其是当客户端正在执行一些重要程序时,应用程序服务器或数据库服务器发生的任何故障都将造成多层应用系统无法正常运作。另外,如果应用程序服务器的负荷过重也会影响整个系统的执行效率,因此对于企业级关键程序,系统的容错能力和负载平衡能力是开发人员必须重视的首要问题。

一般来说,容错能力和负载平衡能力就是让应用程序服务器在多个机器上执行,当客户端应用程序执行时,可以连接到任何一台机器中的应用程序服务器要求服务,以确保系统稳定,同时平衡每一台服务器的负荷。

然而,当应用程序服务器执行于多台机器时,又给数据库服务器提出了新的挑战:一方面,如果所有的应用程序服务器都通过同一远程数据库服务器访问数据,那么数据库服务器的故障同样会影响整个系统的稳定性,而且可能超负荷工作;另一方面,如果每一个应用程序服务器都拥用各自的数据库服务器或本地数据库,这样虽能提高系统的稳定性,但不能保证数据的一致性。

基于以上情况,本文提出了基于MIDAS的应用程序服务器镜像技术方案和实现方法,用以开发安全坚固的分布式系统。

二、安全坚固的多层应用系统

1.多层分布式系统结构

一个多层分布式应用系统被分割成在不同机器上协同运行的逻辑单元。各逻辑单元通过局域网或Internet共享数据和通信,这种结构具有集中控制的商业逻辑、瘦客户端应用程序等许多优点。多层分布式系统最典型的模式为三层结构,各部分的名称和功能如下:客户端应用程序在用户机器上提供用户界面;应用程序服务器位于可连接到所有客户端的中央网络位置,并提供公共的数据服务。应用程序服务器可运行于多个机器上;远程数据库服务器提供数据库管理系统(RDBMS)。

MIDAS(Multi-tier

Distributed Application Services

Suite)即多层分布式应用程序服务器,是Inprise提供的集成了多种技术规范的多层分布式数据库解决方案,是由Borland C++Builder(BCB)/Delphi用来开发多层应用系统使用的中介透明引擎,它具有在客户端无需任何数据库工具可以读取远程数据、网络通信量小、多线程、数据库自动约束及平衡负载的特点。如图1所示的三层结构是多层分布式系统的典型代表。

2.开发具备容错能力的应用系统

多层应用系统的容错能力就是让应用程序服务器在多个机器上执行,当客户端应用程序执行时可以连接到任何一台机器中的应用程序服务器要求服务。如果客户端应用程序连接的服务器发生任何问题而无法继续执行时,客户端应用程序可以立刻连接到其他机器中的服务器继续要求服务。

图1基于MIDAS的三层应用系统的结构

开发具备容错能力的多层应用系统,在应用程序服务器端与平常的系统没有什么区别,而在客户端应用程序中必须配合MIDAS编写一些额外的代码来实现容错能力。

实现容错能力的观念很简单,当客户端应用程序连接到应用程序服务器之后,它就可以向服务器要求服务。但是当应用程序服务器故障时,客户端应用程序如果向服务器要求服务,那么客户端应用程序就会产生一个错误例外。此时客户端可以调用TSimpleObjectBroker的SetConnectStatus方法以设定目前的应用程序服务器成为不堪使用状态,然后再调用GetComputerForProgID方法要求取得另外一个可以使用的机器,以便在这个新的机器中连接提供相同服务的应用程序服务器。最后再调用新的服务器以取得服务。这个切换过程可以用图2来说明。

图2实现容错能力的流程图

3.开发具备负载平衡能力的应用系统

负载平衡的观念是指当有多个能够执行相同应用程序服务器的机器时,当有许多客户端应用程序需要连接应用程序服务器时,多层系统能够分配不同的客户端应用程序到每一个机器中,以便平衡每一个应用程序服务器的负荷。BCB的TSimpleObjectBroker提供了负载平衡的功能,程序员只需将其属性LoadBalanced设为True就可以提供简单的负载平衡能力。

三、镜像技术

由于多层应用系统可能运行于不同地域的不同机器上,设计者永远无法预测多层应用系统在执行时会发生什么状况,因此在分布式计算环境中,多层应用系统除了必须能够正确而且有效率地运作之外,系统的负载平衡能力和容错能力也非常重要。

多层应用系统的容错能力和负载平衡都要求应用程序服务器在多个机器中执行,对于数据库服务器,将有两种可能的连接方式:一种是多个应用程序服务器都与同一个远程数据库服务器连接。采用这种连接方式时,系统的稳定性较低,如果远程数据库服务器故障,整个多层应用系统将无法正常运作;另一种是每一个应用程序服务器均与各自的数据库服务器或本地数据库相连。采用这种方式虽然可以提高系统的稳定性,但各服务器之间的数据互不相同,客户端取得的数据就会不完整或不一致。

为了使多层应用系统既具有稳定性,又能保持数据的完整性,在实际应用中我们采用第二种连接方式,并在应用程序服务器中添加额外的代码,使各服务器之间的数据保持一致,我们称这种方法为应用程序服务器镜像技术。本文以双服务器为例来说明服务器镜像技术的原理及实现方法。

1.动态服务器镜像技术

动态服务器镜像就是当多层应用系统中有多个应用程序服务器提供数据服务时,使各服务器中的数据动态地保持一致。

动态服务器镜像的原理如图3所示,当连接服务器1的客户端应用程序(如客户A)要求更新数据时,服务器1将数据更新到数据库1,同时还将这些数据传送给服务器2,由服务器2负责更新至数据库2;同理,连接服务器2的客户端应用程序(如客户B)更新的数据也会同时更新到两个数据库管理系统中。这样,两个互相独立的数据库管理系统中的数据就能够保持一致。

图3应用服务器镜像示意图

在BCB/Delphi中,提供者组件(TdataSetProvider)负责将数据封装进数据包,然后发送给客户端数据集,并更新从客户端数据集接收到的数据。提供者组件的大多数工作是自动进行的,不需要在提供者组件中编写任何程序代码就可创建具有完整功能的应用程序服务器。然而,提供者组件包括一定的事件和属性,它们允许应用程序服务器更直接地控制为客户端封装的信息以及应用服务器如何响应客户端请求。利用其中的OnUpdateData事件或BeforeUpdateRecord事件即可实现动态服务器镜像。使用OnUpdateData事件可以处理完整的Delta包,而使用BeforeUpdateRecord事件可以对更新的记录逐一地进行处理。

2.静态数据对照

在多层应用系统的运作过程中,如果一个或多个服务器故障,在容错技术的支持下,虽然系统仍能正常运作,但客户更新的数据不能记载到故障服务器的数据库中,数据的完整性便得不到保障。为此,采用了静态对照的方法,即当故障服务器修复并重新投入运行时,主动与其他服务器对照,以提取最新的数据,从而保证客户端应用程序始终得到一致的数据服务。

数据对照可以采用自动对照,也可以由管理员根据具体情况,人为地进行对照。自动对照就是,当应用程序服务器启动时,自动与在线的某一服务器对照数据;人为对照则是,开发专用的对照程序,由系统管理人员根据情况,决定何时进行数据对照。

四、实现方法

1.动态服务器镜像

在服务器端,利用提供者组件的OnUpdateData事件可以在服务器更新数据之前将客户端应用程序传来的数据更新到镜像服务器中,以实现应用程序服务器镜像,使各服务器之间的数据动态地保持一致。

客户端的更新请求包括修改、插入和删除三种。OnUpdateData事件处理函数应分别进行处理,下面给出的代码,以插入操作为例来说明应用程序服务器镜像技术的实现方法:

void __fastcall

TmsRDM::DataSetProvider1UpdateData(TObject

*Sender,

TCustomClientDataSet

*DataSet)

{

TClientDataSet *table; //table连接到镜像服务器

TDateTime dtValue=StrToDateTime(Now()); //当前时间

table=mTable;

table->Active=false;

DataSet->First();

if(Form1->SocketConnection1->Connected)

{

while(!DataSet->Eof)

{

switch(DataSet->UpdateStatus())

{

case

usUnmodified: //处理修改的数据

table->Active=false;

//向服务器传递SQL

table->CommandText=AnsiString("select * from

demo where编号='")

+DataSet->FieldByName("编号")->AsString

+"'

and姓名='"+DataSet->FieldByName("姓名")->AsString+"'";

table->Active=true; //查询

if(table->RecordCount>0) //镜像服务器中已存在该记录,则修改

table->Edit();

else

{ //不存在则添加此记录

able->Append();

for(int

i=0;iFieldCount;i++)

if(DataSet->Fields->Fields[i]->AsString!="")

table->Fields->Fields[i]->AsString=DataSet->Fields->Fields[i]->AsString;

}

DataSet->Next(); //修改状态下,DataSet中有两条相邻的记录说明修改情况,

//前一条是原始数据,后一条是修改的数据

DataSet->Edit();

DataSet->FieldByName("DATE_TIME")->AsDateTime=dtValue;

//记录修改时间

DataSet->Post();

for(int

i=0;iFieldCount;i++)

if(DataSet->Fields->Fields[i]->AsString!="")

table->Fields->Fields[i]->AsString=DataSet->Fields->Fields[i]->AsString;

table->FieldByName("DATE_TIME")->AsDateTime=dtValue;

//记录修改时间

table->Post();

break;

case

usInserted: //处理插入记录

DataSet->Edit();

DataSet->FieldByName("DATE_TIME")->AsDateTime=dtValue;

DataSet->Post();

table->Active=false;

table->CommandText=AnsiString("select

* from demo where编号='")

+DataSet->FieldByName("编号")->AsString

+"'

and姓名='"+DataSet->FieldByName("姓名")->AsString+"'";

table->Active=true;

if(table->RecordCount>0)

table->Edit();

else

table->Append();

for(int

i=0;iFieldCount;i++)

if(DataSet->Fields->Fields[i]->AsString!="")

table->Fields->Fields[i]->AsString=DataSet->Fields->Fields[i]->AsString;

table->FieldByName("DATE_TIME")->AsDateTime=dtValue;

table->Post();

break;

case

usDeleted: //删除记录

table->Active=false;

table->CommandText=AnsiString("select

* from demo where编号='")

+DataSet->FieldByName("编号")->AsString

+"'

and姓名='"+DataSet->FieldByName("姓名")->AsString+"'";

table->Active=true;

if(table->RecordCount>0) //镜像服务器中存在此记录则删除

table->Delete();

break;

}

table->ApplyUpdates(-1);

table->Active=false;

DataSet->Next();

}

}

//记录修改时间

DataSet->First();

while(!DataSet->Eof)

{

switch(DataSet->UpdateStatus())

{

case

usUnmodified:

DataSet->Next();

DataSet->Edit();

DataSet->FieldByName("DATE_TIME")->AsDateTime=dtValue;

DataSet->Post();

break;

case

usInserted:

DataSet->Edit();

DataSet->FieldByName("DATE_TIME")->AsDateTime=dtValue;

DataSet->Post();

break;

}

DataSet->Next();

}

DataSet->First();

//实际更新时从第一条记录开始

}

2.容错处理

在客户端更新数据时,若原先连接的服务器故障,用以下代码能自动连接到提供相同服务的机器,继续取得数据服务:

if (ClientDataSet1->ChangeCount > 0)

{

try {

ClientDataSet1->ApplyUpdates(-1); //数据更新

ClientDataSet1->Refresh();

}

catch(...)

{

SimpleObjectBroker1->SetConnectStatus(

SocketConnection1->Address,false); //记录服务器失败

SocketConnection1->Connected=false;

SocketConnection1->Address=

SimpleObjectBroker1->GetComputerForProgID("mirrorserver.msRDM");

SocketConnection1->Connected=true;

updateBtn->Click(); //用新的服务器更新

}

}

3.静态数据对照

Table1->Active=true;

ClientDataSet1->Active=true;

while(!ClientDataSet1->Eof)

{

AnsiString Filter,Num,Name;

Num=ClientDataSet1->FieldByName("编号")->AsString;

Name=ClientDataSet1->FieldByName("姓名")->AsString;

Filter=AnsiString("编号='")+Num

+"'

and姓名='"+Name+"'";

Table1->Filter=Filter; //设置过滤器,用于条件导航

if(Table1->FindFirst())

{ //如果存在相同的记录

if(Table1->FieldByName("DATE_TIME")->AsString

!=ClientDataSet1->FieldByName("DATE_TIME")->AsString)

Table1->Edit(); //更新时间不同时,修改

else

{

ClientDataSet1->Next();

//数据相同时,继续处理下一记录

continue;

}

}

else

{ //不存在时,插入记录

Table1->Insert();

}

for(int

i=0;iFieldCount;i++) //使两个服务器的数据一致

Table1->Fields->Fields[i]->AsString

=ClientDataSet1->Fields->Fields[i]->AsString;

Table1->Post();

ClientDataSet1->Next();

}

Table1->Active=false;

ClientDataSet1->Active=false;

4.软件握手

软件握手是指服务器向在线的某一服务器发送启动或关闭镜像服务请求,并在收到镜像请求后,进行相应的处理。

void __fastcall TForm1::Timer1Timer(TObject

*Sender)

{//用定时器监视镜像状态

if(Mirror)

{

Timer1->Enabled=false;

Button1->Click(); //连接镜像服务器

}

else

if(SocketConnection1->Connected) {

Timer1->Enabled

=false;

ClientDataSet1->DataRequest(AnsiString("Mirror")); //发送启动请求

}

}

void __fastcall TForm1::FormClose(TObject

*Sender, TCloseAction &Action)

{//服务器关闭时,通知与其有镜像关系的服务器

if(SocketConnection1->Connected)

{

ClientDataSet1->DataRequest(AnsiString("Close")); //停止镜像服务

SocketConnection1->Connected=false;

ShowMessage("关闭服务器");

}

if(ChangeIp||(!FileExists("ipaddress.txt")))

{ //保存镜像服务的IP地址

TFileStream *fStream=new

TFileStream("ipaddress.txt",fmCreate);

int size=Edit1->Text.Length();

fStream->Write(Edit1->Text.c_str(),size);

fStream->Size=size;

delete

fStream;

}

}

//处理握手信息

OleVariant __fastcall

TmsRDM::DataSetProvider1DataRequest(TObject

*Sender,

OleVariant

&Input)

{

AnsiString TmpStr=(WideString)Input;

if(TmpStr=="Close")

Form1->SocketConnection1->Connected=false; //与镜像服务器断开连接

else

if(TmpStr=="Mirror")

Form1->Mirror=true; //启动镜像

}

五、结语

通过分析MIDAS容错处理和负载平衡机制,提出了在多服务器系统中的服务器镜像技术,并介绍了服务器镜像技术的原理和实现方法。文中所介绍的服务器镜像技术,只需少量的代码,却能使多层应用系统既具有稳定性,又能保持数据的完整和一致性,在实际应用中加以改进和完善,将有很好的参考和利用价值。

怎么注销midas服务器程序,MIDAS的服务器镜像技术相关推荐

  1. Linux 服务器程序规范、服务器日志、用户、进程间的关系

    文章目录 服务器程序规范 日志 rsyslogd 守护进程 syslog函数 openlog函数 setlogmask函数 closelog函数 用户 进程间的关系 进程组 会话 系统资源限制 改变工 ...

  2. 高性能服务器程序框架,高性能服务器程序框架

    同步I/O模型要求用户代码自行执行I/O操作(将数据从内核缓冲区读入用户缓冲区,或将数据从用户缓冲区写入内核缓冲区),而异步I/O则由内核来执行I/O操作. 同步I/O向应用程序通知的是I/O就绪事件 ...

  3. Unix 网络编程(四)- 典型TCP客服服务器程序开发实例及基本套接字API介绍

    转载:http://blog.csdn.net/michael_kong_nju/article/details/43457393 写在开头: 在上一节中我们学习了一些基础的用来支持网络编程的API, ...

  4. java 守护进程 linux_Java实现Linux下服务器程序的双守护进程

    一.简介 现在的服务器端程序很多都是基于Java开发,针对于Java开发的Socket程序,这样的服务器端上线后出现问题需要手动重启,万一大半夜的挂了,还是特别麻烦的. 大多数的解决方法是使用其他进程 ...

  5. 今日巨大福利,1元体验京东云服务器,附云服务器用法的完整教程

    记得是在2010年,那个时候我刚刚开始接触Android不久,Google也还没有离开中国.当时我在上大三,Google举办了一场Android应用开发中国大学生挑战赛,跃跃欲试的我就和同学组队一起参 ...

  6. 用什么服务器开发小程序,开发小程序用什么服务器系统

    开发小程序用什么服务器系统 内容精选 换一换 按照翻译方式的不同,高级语言通常可以分为两类:一类是编译翻译,一类是解释翻译,分别对应着编译型语言和解释型语言.编译型语言典型的如C.C++语言,都属于编 ...

  7. python 记录日志到日志服务器_Python日志模块的使用与思考:服务器程序将每日日志写入每日日志文件,logging,及,把,每天,到,当天,中...

    需求: 一个Python服务器程序,可能会连续运行几个月,现在需要把每天产生的log信息写入到当天的文件中,即每天产生一个log文件. 使用logging模块编写程序,第一个版本如下: import ...

  8. C/S架构程序多种类服务器之间实现单点登录(转)

    (一) 在项目开发的过程中,经常会出现这样的情况:我们的产品包括很多,以QQ举例,如登陆.好友下载.群下载.网络硬盘.QQ游戏.QQ音乐等,总不能要求用户每次输入用户名.密码吧,为解决这个问题,高手提 ...

  9. SharePoint2013 访问“/”应用程序中的服务器错误。解决方案:

    SharePoint2013 访问"/"应用程序中的服务器错误.解决方案: 在浏览器中键入访问SharePoint服务器地址时,报如下错误 按照,提示修改web.config文件. ...

最新文章

  1. nyoj--1007 GCD
  2. 论文浅尝 | 时序与因果关系联合推理
  3. html语义化标签_5个你可能不知道的html5语义化标签
  4. tomcat源码分析(一)- tomcat源码导入IDEA并正常启动
  5. 一个斐波那契数列题 HDU 2041
  6. MODBUS ASCII协议和RTU协议的比较 -----和利时PLC采用Modbus RTU
  7. 「三分钟系列06」3分钟看懂http与https的区别
  8. python带我起飞 百度云_CentOS/Debian安装人人影视客户端,下载资源并自动上传到OneDrive网盘...
  9. 7.数电复刻 之 门电路
  10. ISSCC2019文章
  11. Eclipse 设置注释模板
  12. 修改计算机用户名bat脚本
  13. 简单人物画像_10天学会画画 第5天:简单人物画法
  14. ZooKeeper系列:Leader选举
  15. 技术书籍也香艳【关于Head First Design Patterns 封面女郎】
  16. matlab中portcons,Matlab在马柯维茨均值-方差模型的简单应用.ppt
  17. linux 修复文件fsck,使用fsck检查并修复文件系统[Linux] | MOS86
  18. enc易能变频_ENC易能变频器专修公司
  19. 课后练习03---126字母邮箱注册功能
  20. 天鹅是白天的月亮(转)

热门文章

  1. MFC添加自定义消息及重写消息过程
  2. C# SQLite 数据库操作语句与文件视图管理器
  3. 快速傅里叶变换(FFT)详解
  4. window 之命令行的cd
  5. java第三周学习总结
  6. 矩阵键盘程序_独立按键与矩阵按键
  7. 树莓派上传数据到onenet云平台
  8. 则执行C语言语句unsigned,部分C语言题目
  9. wordpress mysql 挂了_大神们,诊断一下,wampserver的mysql老是挂掉!
  10. python3.7官网中文官网_通用操作系统服务