一种提高基于构件软件系统可靠性的方法

文档序号:7615177阅读:152来源:国知局
专利名称:一种提高基于构件软件系统可靠性的方法
技术领域
本发明涉及一种应用服务器集群与容错的方法,特别涉及一种提高基于构件软件系统的可靠性方法。
背景技术
服务器端Java平台(J2EE标准)业已成为提供Web信息服务的最佳方法。对于关键业务系统来说,可靠性已成为互连网的一大挑战。直接影响关键业务用户或业务伙伴的故障是无法接受的。基础结构必须具备很高的可用性,才能够向企业提供不间断的服务。
在当今动态业务环境下,为了满足需求,企业必须具备动态提高容量的能力。支持这种应用的基础结构必须具备相当高的伸缩性,以便在不改变软件和硬件的情况下进行接近线性的扩展。因此支持对于J2EE平台的集群,负载平衡和错误恢复,是一个性能优良,可扩展,稳定的应用服务器必须支持的特性。集群是一组相互独立的服务器在网络中表现为单一的系统,并以单一系统的模式加以管理。此单一系统为客户工作站提供高可靠性的服务。多数情况下,集群中所有的计算机拥有一个共同的名称,集群内任意一个系统上运行的服务可被所有的网络客户所使用。集群必须可以协调管理各分离组件的错误和失败,并可透明地向集群中加入组件。一个集群包含多台(至少二台)拥有共享数据存储空间的服务器。任何一台服务器运行一个应用时,应用数据被存储在共享的数据空间内。每台服务器的操作系统和应用程序文件存储在其各自的本地储存空间上。集群内各节点服务器通过内部局域网相互通讯。当一台节点服务器发生故障时,这台服务器上所运行的应用程序将在另一节点服务器上被自动接管。当一个应用服务发生故障时,应用服务将被重新启动或被另一台服务器接管。当以上的任一故障发生时,客户都将能很快连接到新的应用服务上。对于用于大型企业级应用的J2EE服务器来说,集群服务是必要的。但是J2EE规范中并没有对集群方面内容做出规定,所以对于集群的实现都是由具体的服务器来各自决定的。应用服务器作为企业级的应用服务器,需要处理大量且并发的请求,同时这些处理过程中的数据都是重要而不允许出错的。为了提高大量访问情况下的性能以及满足可靠性的要求,应用服务器需要负载均衡和容错的能力,提供应用服务器以下新的特性可扩展性是指一个应用程序能支持不断增长的用户数量的能力。当由于某种需要动态添加和减少服务器,不会对系统造成影响。通常由于系统负载量的增加,需要动态添加新的服务器,因此这对客户的调用应该是透明的,不会中断其他服务器的工作;可靠性可靠性是指系统有一定程度的冗余能力。在集群系统中,某个节点的崩溃不会影响系统的服务,系统能够自动迁移任务,能够处理这个任务的服务器自动处理客户的请求。
从上面集群需要支持的特性可以看出,集群包括了负载均衡和容错两个方面。负载均衡使得服务器群共同分担工作负载,它采用某种负载分配策略,优化服务器的性能。而且所有这些工作对于客户的访问是透明的,不需要客户的干预。理想状况下,如果集群中的每个服务器有着相同的处理能力,那么承担相同的负载量。因此每个负载的分配算法和服务器自身的性能有关,如何收集、处理这些信息,以及采用什么样的算法来分配负载。容错采用多数据复本,允许某种程度的错误和失败。在理想情况下,错误恢复应该对于客户是完全透明的。当一个服务器失败时,正在和这个服务器进行交互的客户能够自动转交为其它服务器。错误恢复的关键点是客户能够持续利用服务器的服务,即使某些应用服务器发生故障,而且在服务器修复之后,立即可以和其它服务器一起提供服务,所有这些仅仅和服务器群有关,客户端完全不需要知道。正如我们上面所分析的,对于用于大型企业级应用的J2EE服务器来说,集群服务是必要的。当前的应用服务器大多不支持细粒度的集群,并且不支持方法级的请求重定向,以及对象组的状态复制技术,J2EE规范中并没有对集群方面内容做出规定,所以对于集群的实现都是由具体的服务器来各自决定的。

发明内容
本发明的目的在于克服上述现有技术的缺点,提供了一种提高基于构件软件系统可靠性的方法,此方法能够实现多个节点的JToneFrame应用服务器集群在不停止服务的情况下,动态加载、删除集群内的节点;支持水平和垂直分割;对象级和方法级EJB容器负载平衡;支持无状态会话Bean,状态会话Bean和实体Bean的集群。为达到上述目的,本发明采用的技术方案是首先由客户通过其客户端组件接口代理发出一个服务器调用请求;遵照EJB2.1规范的EJB组件,在其扩展部署描述符中添加负载均衡和容错功能标签,指示EJB组件支持集群功能和默认采用随机分配负载均衡算法,通过预编译器对EJB组件进行编译,生成相应的EJBHome和EJBObject接口的实现类,并且对其生成实现类的Stub,使用预编译工具改变Stub类原有远程调用的执行逻辑,在每次业务方法调用前,请求服务器端的EJB组件的各个服务器的引用列表,实现请求的再分配;客户的请求随机由服务器群中任一服务器接收,这个服务器使用底层的服务器组通讯协议和其它服务器进行通讯,根据EJB组件的扩展部署描述符,客户根据自己的需要选择负载参数,如果客户有自己定制的负载参数和分配策略,则装载客户自己定制的参数和策略,然后根据装载定制参数和策略模块,在其它服务器上调用负载收集命令,在各个节点收集负载信息;如果客户没有定制此项,服务器可以装载默认的参数和分配策略;定义负载参数系统基本运行环境参数在基于J2EE应用服务器中间件系统中,系统基本运行环境参数定义为JVM的堆大小、使用内存;组件容器组件容器包含Servlet容器和EJB容器,Servlet容器参数包含Servlet运行数量和用户单位事件请求数量,EJB容器参数包括分别为SessionBean组件、EentityBean组件和MessageDriverBean组件而建立的其创建组件数量、运行组件数量、池态组件数量;其它引用的资源按照其类别分为数据源资源、JCA资源、JMS资源,定义其连接数量参数、可用连接数量资源和等待引用资源数量;根据以上的负载参数定义,动态计算当前时刻的服务器负载量Li(t)=αB(t)+βC(t)+λR(t),B(t)表示在时刻t系统基本运行环境负载量,C(t)表示组件容器在t时刻的负载量,R(t)表示t时刻资源引用量,α,β,λ分别表示权重,则t时刻的服务器群的负载总量为L(t)=Σi=1nLi(t),]]>当前时刻的阈值为T(t)=L(t)n,]]>当Li(t)>T(t)时,请求被重定向到一个轻载服务器上运行;根据各个节点收集的负载信息,将整个服务器各个节点负载信息进行加权计算得出其负载值,依据此值进行排序,返回给客户接口代理所有可用的服务器列表;客户根据返回的这个列表顺序选择节点,将负载最轻的节点取出引用,并根据服务器引用发出请求,此时请求将会在轻载节点上进行执行;如果这个节点能够正确处理请求,没有异常抛出,则同步其它节点的状态信息,以保证下一次请求调用和分配的正确性,如果调用不成功,客户端的请求则返回客户节点列表,根据服务器的节点列表选择下一个轻载的服务器节点,调用EJB组件的业务方法,当节点列表的所有节点都发生故障时,客户调用将不会被正确处理。
由于本发明采用分布式负载分配策略,不存在集中的负载分配器,不存在单点失效的可能性,且也不把负载分配器独立出来,而是将负载分配器作为每个节点的一个组件,这样就解决了集中式的问题,把请求的分配分散到各个节点上。


图1是客户端的调用形式图;图2为两个服务器复本节点组成的集群系统。
具体实施例方式
下面结合附图对本发明作进一步详细说明。
为了实现上述的应用服务器集群与容错技术内容,本发明将实施分为EJB组件客户端和服务器端实施方式两个部分,客户端首先由客户通过客户端组件接口代理发出一个服务器调用请求;客户端负责请求转发的工作。这些工作具体都是由RMI体系中的客户代理(Stub)来完成的。客户端Stub将来自客户端的业务方法调用请求发送到任一服务器复本节点上,并且通过将实际调用动作上移到其超类中而实现容错。然后由客户端stub进行请求转发,客户端stub必须持有服务器端的信息,因此在每个服务器节点上同步维护整个服务器组的列表视图,而这个信息就保存在成员域server中。server中的具体内容,是此EJB在各个服务器复本节点上生成的客户端stub(包括home stub和remote stub)。客户端stub只需从其中取出任一服务器节点的stub,获得它的remote reference,用它来替代自身的remotereference,然后让业务方法调用发生在现在的remote reference上,即可顺利的将业务方法调用发送到stub对应的服务器复本节点上。
参见图1,1、客户端Stub在加入了getServerList()方法之后,客户端最初没有进行任何方法调用,server中的内容只有一个,就是持有它的客户端stub本身。
2、在每次客户端进行业务方法调用之前,客户端Stub都会进行getServerList()方法的调用而获得服务器列表,以集群系统的当前服务器复本列表来更新本地的server内容然后返回服务器列表给客户端Stub。getServerList()方法的实现在服务器端的Home/Remote接口的实现类中,所以客户端stub进行的getServerList()方法调用实际上也是一次远程方法调用。
3、当客户端获得了服务器列表后,客户端stub从列表中选取一个节点,再次进行业务方法调用,服务器接收到此业务方法调用后,调用实际部署EJB的Bean实例的方法,然后给客户端返回调用结果。
为了实现以上功能,可以采用代码自动生成技术,并且定义扩展部署描述符,扩展部署描述符遵照EJB2.1规范的EJB组件,在其扩展部署描述符中添加负载均衡和容错功能标签,指示EJB组件支持集群功能和默认采用随机分配负载均衡算法,通过预编译器对EJB组件进行编译,生成相应的EJBHome和EJBObject接口的实现类,并且对其生成实现类的Stub进行修改,改变原有远程调用的执行逻辑,在每次业务方法调用前,请求服务器端的EJB组件的各个服务器的引用列表,可以实现请求的再分配;预编译过程通过如下步骤1、通过部署描述符和反射机制来获取输入的jar文件的元信息,将其与模板文件相结合从而生成EJB实现类的源文件。
2、调用javac编译生成的源文件从而得到类文件。
3、调用rmic来生成相应的stub和skeleton文件。这里保留生成的stub和skeleton的源文件。
4、修改stub和skeleton源文件加入对事务和安全的支持。
5、重新编译修改后的stub和skeleton文件,得到新的类文件。
6、最后以这些生成的类文件来更新输入的jar文件。
7、最终输出内容包括实现类、stub和skeleton类和原有客户端定义的类文件的新的jar(ear)文件。
底层的服务器组通讯协议和其它服务器进行通讯是保障服务器统一视图的标准,是服务器间调用的总线。
1、客户的请求由预编译生产stub代理发起;2、客户的请求随机由服务器群中某个服务器接收,这个服务器使用底层的服务器组通讯协议和其它服务器进行通讯;3、接收请求的服务器节点向其它服务器发出负载收集命令,在各个节点的负载均衡器发出收集负载信息。底层的收集器收集各个节点的系统基本运行环境参数;组件容器,和其它引用资源三类负载参数,动态计算当前时刻的服务器负载量Li(t)=αB(t)+βC(t)+λR(t),B(t)表示在时刻t系统基本运行环境负载量,C(t)表示组件容器在t时刻的负载量,R(t)表示t时刻资源引用量,α,β,λ分别表示权重,每个节点将其当前的负载情况Li(t)返回给请求节点。
4、接收客户请求调用的节点计算t时刻的服务器群的负载总量为L(t)=Σi=1nLi(t),]]>得到当前时刻的阈值为T(t)=L(t)n,]]>经过节点信息收集和负载量计算,将serverList中各个节点的stub按照负载优先级排序,并通过getServerList()方法将经过排序的serverList传送给客户端stub。当前节点的服务器量Li(t)>T(t)时客户端stub按照serverList顺序调用服务器端集群系统服务器端的主要要求,就是要使得每一个服务器复本节点在任意时刻对于一个特定客户端来说都是完全相同的,也即状态一致。根据EJB生命的周期,对一个EJB来说,它的集群系统服务器端有这样3个阶段1、创建EJB在某个节点上调用了创建方法,使得此节点可以接收此EJB的方法调用。那么,此时集群系统中的其它节点也需要进行某些创建工作,使得它们中的任何一个都可以接收此EJB的方法调用。
2、方法调用(即一个EJB的使用过程)对于无状态会话Bean,因为Bean不保存状态,所以无需做什么;而对于有状态会话Bean和实体Bean,因为Bean保存状态,所以在每次方法调用时还需要进行状态复制,使得所有节点对于此EJB状态一致,从而可以实现透明迁徙。
3、移除EJB在某个节点上调用了移除方法,则此节点此后将无法接收此EJB的方法调用请求。集群系统中的其它节点也要进行移除工作,使得每一个节点都无法接收此EJB的方法调用请求。
每种类型的EJB有不同对于以上的处理有不同处理方式,服务器端的具体设计,将分为有状态会话Bean,实体Bean和无状态会话Bean,三种Bean的服务器端实现基本相比,因此首先对状态会话Bean的实施进行详细描述,再对实体Bean和无状态会话Bean的特殊部分进行补充。
4、状态会话Bean(Stateful Session Bean)实现有状态会话Bean的集群有几个具体问题要考虑首先,需要考虑复制那些状态;其次,进行状态复制时要在不同的节点间具有正确的对应关系;同时,还要考虑钝化和激活操作对于状态复制的影响。容器是EJB组件的运行环境,容器初始化虽然不是一个EJB生命周期的一部分,但是在集群中也担任了重要的工作,即将EnterpriseContextRequestMessage和EnterpriseContextReplicationWrap类实例注册到状态管理器,并将home实现类实例注册到复制管理器以将此节点加入对于home stub的serverList中。
容器的创建过程1、创建过程由客户端调用home接口中的create()方法开始;2、经过实例拦截器时,将会为此创建操作关联一个新的context实例;3、在容器类中,首先调用Bean实现类实例的ejbCreate()方法。然后赋给context实例一个id,为了在整个集群系统中具有唯一的名称,id改为节点名和只增的长整型值组成,这样的id在集群系统中是唯一的。接下来是启动ejbObject实例,将其发布到rmi端口使其对于客户端可用,同时将ejbObject注册到复制管理器以将此节点加入serverList中。
4、方法调用返回实例拦截器时,如果创建成功则将此context插入cache,并向其它节点发送创建的要求,而结果则返回客户端。
业务方法调用过程1、业务方法的调用过程由客户端调用Remote接口中的业务方法开始;2、经过实例拦截器时,从cache中取出对应id的context实例,并且在进入下一个拦截器前,首先发送一个保持的消息。接收到这个消息的其它节点,会锁定其上具有同样id值的context实例。因为此次方法调用应该对于所有节点具有同样的影响,所以要防止其它节点上的同值context实例在此节点进行方法调用期间被钝化甚至被删除。
3、在结束方法调用返回实例拦截器时,无论调用成功与否都要进行状态同步的工作,即将context实例包装之后发送给其它所有节点。
4、其它节点接收到状态同步要求之后的响应工作主要有两方面一是本节点上context实例的instance引用将指向接收到的instance实例,以同步instance实例的状态变化;二是本节点上的locked值置为接收到的locked值,以同步context实例的调用状态。
5、后创建过程是一个特殊的创建过程。在一个新的节点加入集群系统后,如果它接收到一个EJB的业务方法状态同步要求,那么因为在此新节点上并没有创建此EJB,因此首先要进行后创建过程。
移除过程1、移除过程由客户端调用Remote接口中的remove()方法开始。
2、经过实例拦截器时,与一般业务方法调用相同。
3、在容器类中,首先停止ejbObject实例,使其对于客户端不可用;然后调用ejbRemove()方法;最后将context实例的id置为null。
4、结束方法调用实例拦截器时,因为context实例的id被置为null,所以此context实例将被从cache中移除。
服务器端状态同步参见图2,图2为为两个服务器复本节点组成的集群系统,表示了在nodel上进行方法调用以及状态复制的完整过程。图2中分别是前面的创建过程、业务方法调用过程、响应创建过程和响应业务方法状态同步过程。
1、客户的方法调用由节点1接收,方法分为两种类型Home接口的创建方法和业务方法调用。
2、如果是Home接口的创建方法,首先在节点1进行组件对象创建,然后进行状态同步方法。节点2接收到状态同步方法,判断同步方法的类型,如果是Home创建方法,则在节点2创建相同的对象实例,完成同步处理后,由节点1返回调用结果给客户。
3、如果是业务方法调用,首先根据客户调用方法的Id从Cache中取出对应的对象上下文(EnterpriseContext),同时发出上下文锁请求(LockingRequest),节点2从Cache中取出对象上下文,进行锁定操作(setLock),使其处于等待状态(Wait)。然后节点1处理业务方法调用,完成后,进行状态同步。节点2接收到同步方法调用,进行业务方法的同步操作,同步对象实例的状态属性。完成同步操作后,由节点1返回调用结果给客户。
4、如果节点2已经创建了EJB对象实例,只要同步本次业务方法调用的状态,否则首先在节点2进行EJB对象实例的创建过程,然后和节点1的状态同步。
容错过程1、如果客户端调用返回正确结果,则调用完成。
2、如果客户的调用捕捉到IOException或者为RunTineException则从ServerList中选取次轻负载节点,继续向其它服务器进行业务方法调用。
3、如果ServerList中可用节点为空,并且没有返回正确结果,则调用失败。
实体Bean(Entity Bean)基本和状态会话Bean的过程相同,不同在于一个有状态会话Bean的生命周期是由create方法调用开始的,而一个实体Bean的生命周期可以由create方法调用开始,也可以由finder方法调用开始。
finder方法又分为单数查找和复数查找过程单数查找只返回一个ejbObject实例,而复数查找返回一批ejbObject实例。单数查找过程和创建过程很类似,而复数查找过程则只是创建一批ejbObject实例并启动,其它工作则等到具体通过某个ejbObject实例进行方法调用时才进行。因此,这里将create过程和单数finder过程通称单数过程,而将复数查找过程成为复数过程。
对于单数过程和复数过程的同步响应也不相同单数过程和有状态会话Bean的响应创建基本相同,只是并不复制instance实例,仅将valid置为false;复数过程则从ejbObjectIdList中获得id列表,在本地创建这些ejbObject实例并启动,其它工作则等到具体通过某个ejbObject实例进行方法调用时才进行。
业务方法调用过程可以说与有状态会话Bean的业务方法调用过程是相同的。唯一的不同就是不复制instance实例,只是将本地context实例的valid置为false,强迫它进行方法调用之前从数据库获得同步无状态会话Bean(Stateless Session Bean)无状态会话Bean由于不持有状态,所以与前两种Bean有着较大的区别。但是基本的设计并没有大的差别,下面仍然只叙述不同于有状态会话Bean的部分。
容器初始化无状态会话Bean的容器在启动之后即将自身实例挂载到一个全局访问点上。这个全局访问点即静态成员变量containerList,它持有一个节点上所有已经启动的无状态会话Bean容器类实例。
业务方法调用和后创建对于没有状态的无状态会话Bean来说,是无需状态同步的,所以在进行业务方法调用时将不会对其它节点提出任何状态同步要求。因为这个原因,无状态会话Bean的后创建工作无法由Bean本身来主动发起,因为Bean完全无法知道是否有新的节点加入。
所以,无状态会话Bean的后创建工作可以采用了一种比较曲折的方式当集群中的节点感觉到有新的节点加入时,它就会通知所有已经在本节点启动的无状态会话Bean容器,而相对于这些容器的Bean将在下一次业务方法调用(remove()方法除外)时向其它节点发出创建的要求。接收到创建要求的节点则检查自身,如果已经创建过了就置之不理,否则就进行后创建工作。
以上对应用服务器集群几个关键实施技术进行了详细的说明,并且这些实施过程在JToneCluster集群服务器中都得到了验证,应用服务器只要遵循以上的技术实施方案都可以实现高可靠和高性能的服务器群。
权利要求
1.一种提高基于构件软件系统可靠性的方法,其特征在于1)首先由客户通过其客户端组件接口代理发出一个服务器调用请求;2)遵照EJB2.1规范的EJB组件,在其扩展部署描述符中添加负载均衡和容错功能标签,指示EJB组件支持集群功能和默认采用随机分配负载均衡算法,通过预编译器对EJB组件进行编译,生成相应的EJBHome和EJBObject接口的实现类,并且对其生成实现类的Stub,使用预编译工具改变Stub类原有远程调用的执行逻辑,在每次业务方法调用前,请求服务器端的EJB组件的各个服务器的引用列表,实现请求的再分配;3)客户的请求随机由服务器群中任一服务器接收,这个服务器使用底层的服务器组通讯协议和其它服务器进行通讯,根据EJB组件的扩展部署描述符,客户根据自己的需要选择负载参数,如果客户有自己定制的负载参数和分配策略,则装载客户自己定制的参数和策略,然后根据装载定制参数和策略模块,在其它服务器上调用负载收集命令,在各个节点收集负载信息;如果客户没有定制此项,服务器可以装载默认的参数和分配策略。4)定义负载参数系统基本运行环境参数在基于J2EE应用服务器中间件系统中,系统基本运行环境参数定义为JVM的堆大小、使用内存;组件容器组件容器包含Servlet容器和EJB容器,Servlet容器参数包含Servlet运行数量和用户单位事件请求数量,EJB容器参数包括分别为SessionBean组件、EentityBean组件和MessageDriverBean组件而建立的其创建组件数量、运行组件数量、池态组件数量;其它引用的资源按照其类别分为数据源资源、JCA资源、JMS资源,定义其连接数量参数、可用连接数量资源和等待引用资源数量;5)根据以上的负载参数定义,动态计算当前时刻的服务器负载量Lt(t)=αB(t)+βC(t)+λR(t),B(t)表示在时刻t系统基本运行环境负载量,C(t)表示组件容器在t时刻的负载量,R(t)表示t时刻资源引用量,α,β,λ分别表示权重,则t时刻的服务器群的负载总量为L(t)=Σt=1nLi(t),]]>当前时刻的阈值为T(t)=L(t)n,]]>当Li(t)>T(t)时,请求被重定向到一个轻载服务器上运行;6)根据各个节点收集的负载信息,将整个服务器各个节点负载信息进行加权计算得出其负载值,依据此值进行排序,返回给客户接口代理所有可用的服务器列表;7)客户根据返回的这个列表顺序选择节点,将负载最轻的节点取出引用,并根据服务器引用发出请求,此时请求将会在轻载节点上进行执行;8)如果这个节点能够正确处理请求,没有异常抛出,则同步其它节点的状态信息,以保证下一次请求调用和分配的正确性,如果调用不成功,客户端的请求则返回客户节点列表,根据服务器的节点列表选择下一个轻载的服务器节点,调用EJB组件的业务方法,当节点列表的所有节点都发生故障时,客户调用将不会被正确处理。
全文摘要
一种提高基于构件软件系统可靠性的方法,此方法采用分布式负载分配策略,能够实现多个节点的JToneFrame应用服务器集群在不停止服务的情况下,动态加载、删除集群内的节点;支持水平和垂直分割;对象级和方法级EJB容器负载平衡;支持无状态会话Bean,状态会话Bean和实体Bean的集群。不存在单点失效的可能性,且也不把负载分配器独立出来,而是将负载分配器作为每个节点的一个组件,这样就解决了集中式的问题,把请求的分配分散到各个节点上。
文档编号H04L12/24GK1710865SQ20051004287
公开日2005年12月21日 申请日期2005年6月30日 优先权日2005年6月30日
发明者赵天海, 侯迪, 赵季中, 齐勇, 郗旻 申请人:西安交通大学
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1