翻译 TianYu 2002-12-13
http://www.javaworld.com/javaworld/jw-02-2001/jw-0223-extremescale_p.html
摘要
如果你计划建立一个可伸缩的,可用的网站,那么你就需要理解群集.在这篇文章里, Abraham Kang介绍了J2EE群集,说明如何实现群集, 调查了Bluestone Total-e-server, Sybase Enterprise Application Server, SilverStream Application Server, 和 WebLogic Application Server在方法上如何不同.掌握了群集知识,你将能够设计和实现有成效的J2EE应用.
在Web上企业正在选择Java 2, Enterprise Edition (J2EE)产生他们关键性任务的应用.在J2EE框架里, 集群提供了保证最少下载时间和最大伸缩性的关键性任务服务.集群是在一组应用服务器显式运行你的J2EE应用,就象一个实体一样, 对于伸缩来说,你以后会在集群里引入额外的机器.确定集群的每个组件都是冗余的,来保证最少的下载时间.
在这篇文章里,我们将对群集,群集方式和重要的集群服务有个基本的理解.由于群集方式在行业应用里是多样的,所以我们将调查每种方式的好处和缺点.另外,我们也将寻找集群在应用服务器里重要的相关特点,并进行讨论.
为了把我们新获得的群集知识应用到现实世界,我们将了解HP Bluestone Total-e-Server 7.2.1, Sybase Enterprise Application Server 3.6, SilverStream Application Server 3.7和 BEA WebLogic Server 6.0它们每一个是如何实现集群的.
在后续的第二部分里,包括群集的编程和失败转移策略.也测试了四个应用服务器产品,了解他们如何伸缩和失败转移的.
集群定义
J2EE应用服务器提供商给集群下了定义, 一个集群就是一组在一起工作,显式提供企业服务(支持JNDI,EJB,JSP, HttpSession和组件失败转移等等)的机器群.他们特意给出了含糊不清的定义,因为每个提供商实现群集是有差异的.有些提供商把一个分发器放到一组独立的机器前面, 在集群里这些机器彼此之间互不了解.在这个方案里,分发器从用户那里收到一个初始的请求,然后由集群里具体的成员服务器通过HTTP把头重定向到客户端应答. 另一些提供商实现了一个紧密的,完整的机器联盟,每个机器都随着那些机器上的对象知道它周围的其他机器.
除了机器外,集群可以包括冗余和失败转移的能力.
· ·负载均衡器(Load balancers):
进入集群和通行指示器到单个Web或应用服务器的唯一入口点
·Web servers
·网关路由器(Gateway routers) 在内网外的的出口点.
·多层交换器(Multilayer switches)
包和帧过滤确保在集群里的每个机器仅仅收到相关机器的信息.
·防火墙(Firewalls)
集群保护器通过端口过滤防止Hackers访问集群和内网
·存储区域网络交换器(SAN---Storage Area Networking switches)
连接应用服务器,web服务器,和数据库到一个后端存储媒介;
管理写数据到物理硬盘;还有失败转移.
·数据库(Databases)
不管他们是如何实现的,所有的集群都提供两个好处:可伸缩性(scalability)和高可用性(high availability---HA)
可伸缩性(scalability)
伸缩性支持用户增长时保证应用服务质量的能力.集群允许你依靠增加额外的服务器提供额外的容量,因而保证伸缩性.
高可用性(high availability---HA)
HA能被一个词概括:冗余.集群使用许多的机器处理服务请求.因此,如果在集群里的任何机器失败,另外一台机器会直接接管.
集群仅仅在应用服务器层提供HA.对于一个要展示真正HA的Web系统,一定象诺亚方舟一样至少包括Web服务器,网关路由器, 交换基础设施,等等中的两种.(关于HA的更多内容,看这个HA Checklist.)
集群类型
J2EE集群通常流行两种风格:非共享和共享磁盘.在非共享集群里, 每个应用服务器都有的它自己的文件系统, 和这个集群里运行的应用程序自己的拷贝相一致.应用的更新和增加需要更新集群里的每个节点.当代码增加和更新发布时进行配置,大的集群有恶梦般的维护.
相反,磁盘共享集群使用一个所有的应用服务器都用的存储设备来获取在集群里运行的应用.更新和增加出现在一个文件系统里,集群里的所有的机器可以访问这些变化.直到最近才发现, 单点失败是这种方法的不利方面.然而,SAN给出了一个单独的逻辑接口,通过这个接口可以进入到一个提供失败转移,反馈,和伸缩性的冗余存储中介.(关于SAN更多的内容,看Storage Infrastructure)
当比较J2EE应用服务器的集群实现时,重要考虑:
·集群实现
·集群和组件失败转移服务
·HttpSession失败转移
·集群拓扑里的单点失败
·柔性拓扑规划
·维护
以后我们将看到四种流行的应用服务器在不同领域如何比较,但是,首先还是让我们更详细的检查所要考虑的每一项.
集群实现
J2EE应用服务器在他们的JNDI(java命名和目录接口)实现周围实现了群集.虽然JNDI是J2EE应用依赖的核心服务,但是它很难在集群里实现,因为它不能把多个对象绑定在单个名字上.关于每个应用服务器的JNDI实现有三个普遍的群集方法.
·独立的
·中央集中的
·全局共享的
独立JNDI树
HP Bluestone Total-e-Server 和SilverStream Application Server利用了一个适合于每个应用服务器的独立JNDI树.在一个独立JNDI树的集群里成员服务器不知道或不关心集群里其他服务的存在.因此,不支持失败转移或者通过重定向HTTP或EJB请求的媒介服务提供支持.配置媒介服务,使他们知道集群里每个组件都驻留在哪里和万一失败发生如何得到一个替代的组件.
独立JNDI树的集群它的一个优点:更短的集群收敛时间和灵活的伸缩.集群收敛衡量了集群完全知道集群里所有的机器和相关对象的时间.然而, 在一个独立JNDI树的集群里收敛(Convergence)并不是一个要关心的问题,因为集群在两台机器一启动就完成了收敛(Convergence).独立的JNDI树的其他优点:伸缩仅仅需要需要增加额外的服务器.
然而,也存在几个弱点.首先,失败转移通常是开发者的责任. 也就是说,因为每个应用服务器的JNDI树都是独立的,所以通过JNDI重新找到的远程代理被固定到已出现的lookup服务器上.在这种情况下,如果调用EJB的一个方法失败了,开发者必须写额外的代码连接到分发器来获得另外一个活动服务器的地址,做另外一次JNDI查找,再一次调用已失败的方法. Bluestone实现了一个更复杂的独立JNDI树的形式,就是每个请求都经过EJB代理服务或者代理LBB (Load Balance Broker).EJB代理服务保证每个EJB请求都进入一个活动的UBS实例.这种方案对每个请求都添加了额外的反应时间,但是在方法调用之间允许自动的失败转移.
中央集中JNDI树
Sybase企业应用服务器实现了一个中央集中JNDI树的集群.根据这种设置,中央集中的JNDI树利用了CORBA的CosNaming服务.命名服务器收容了集群的中央集中的JDNI树,清楚哪个服务器出事了.刚一启动,集群里的每个服务器就绑定它的对象到它的JNDI树和所有的命名服务器.
在一个中央集中JNDI树的集群里获得一个EJB的引用需要两个步骤.首先,客户端从命名服务器查找一个home对象,返回一个互操作对象引用(IOR).一个IOR指向集群里活动的具有home对象的几台机器.第二,客户端挑选出定位在IOR里的第一个服务器,得到home和remote.如果在EJB方法调用之间出现失败,CORBA stub实现了重新获得另外一个home或者remote的逻辑.这个home或者remote来自从命名服务器返回的IOR里列出的一个替代服务器.
命名服务器本身就证实了中央集中JNDI树集群的一个弱点.如果你有特定的50台机器的集群,之中有5台是命名服务器,如果5台命名服务器都down掉了,那么这个集群就变的没什么用了.当然,另外45台机器能运行,但是当命名服务器down了,这个集群将不能为一个EJB客户端服务.
如果集群原先的命名服务器全部发生了失败, 在线引进一个额外的命名服务器就会出现另一个问题. 假如这样做的话,一个新的中央集中命名服务器就需要集群里每个活动机器绑定它的对象到新的命名服务器的JNDI树.虽然当绑定过程发生时开始收到请求是可能的,但不推荐这样做,因为绑定过程延长了集群的恢复时间.此外,来自一个application或者applet的JNDI lookup,事实上出现了两次网络调用.第一个调用从命名服务器重新获得一个对象的IOR,第二的调用从IOR里指定的一个服务器那重新获得客户端想要的对象.
最后,当集群数量增长时中央集中JNDI树的集群承担收敛(Convergence)所带来的增加时间.就是说当你伸缩你的集群时,你必须增加更多的命名服务器. 紧记命名服务器所在的机器和全部的集群机器通常公认的比率是1:10,两个命名服务器是最小数目.因此,如果你有一个10台机器的集群和两台命名服务器,在服务器和命名服务器之间绑定的总数能达到20,在一个40台机器的集群和四台命名服务器里,会有160个绑定关系.每个绑定都表示其中一个成员服务器绑定所有的对象到一个命名服务器的JNDI树的过程.记住,中央集中JDNI树的集群在所有的JNDI集群实现之间具有更糟糕的收敛时间(Convergence time).
全局共享JNDI树
最后,BEA Weblogic实现了一个全局共享的JNDI树.用这种方式,当集群里的一个服务器启动时,通过IP广播宣布它的存在并且把JNDI树通知给集群里的其它服务器.群集里的每个机器既绑定它的对象到全局共享JNDI树,又绑定到它自己的本地JNDI树.
在每个成员服务器里都拥有一个全局的和本地的JNDI树,允许生成的home和remote stubs失败转移,并且提供很快的进程里的JNDI lookups. 全局共享JNDI树在集群里的所有机器之间都是共享的,允许任何成员机器知道集群里所有对象的精确位置.如果在集群里的多个机器上对象是可用的,一个特殊的home对象被绑定到全局共享JNDI树.这个特殊的home知道所有EJB对象和与它相关联对象的位置, 也生成知道所有EJB对象和与它相关联对象的位置的remote对象.
全局共享方式的主要不利方面:当服务器启动时所产生的大量网络初始化传输和集群的过分收敛时间(Convergence time).相反,在一个独立JNDI树的集群里, 由于没有JNDI共享信息出现,所以收敛并不被看做是个问题.然而,对集群里所有机器来说, 一个全局共享或者中央集中的集群,建立全局共享或者中央集中JNDI树都需要花费时间. 实际上,因为全局共享集群使用广播传输JNDI信息,建立全局共享JNDI树所需的时间与以后增加的服务器数相比是线性相关的.
全局共享与中央集中JNDI树的集群相比主要的好处集中在自由伸缩和高可用性.使用全局共享,你就不必在专门的命名服务器上乱动CPU和RAM,不必在集群里调整命名服务器的数目.当然,为了伸缩应用程序,仅仅增加更多的机器就可以.此外,如果集群里的一些机器down掉了,集群将完全继续起作用.最后,和在中央集中JNDI树的集群里每个remote lookup都需要两个网络调用相比, 每个remote lookup都只需要一个单一的网络调用.
所有这些都应该打个折扣,不可全信.因为运行在应用服务器上的JSPs,servlets,EJBs,和JavaBeans可以共处在EJB服务器里.他们总是使用一个进程里的JNDI lookup.紧记,如果你只运行服务器端(server-side)应用,那么在独立的,中央集中的,或者全局共享的集群实现几乎没有什么差别. 实际上,每个HTTP请求在应用服务器上都将结束,因为应用服务器将使用进程里的JNDI lookup返回你server-side服务器里使用的一些对象.
下面,把我们的注意力转到J2EE应用服务器里第二个需要考虑的事情:集群和失败转移服务.
集群和失败转移服务.
在一台机器上提供J2EE服务与通过集群提供相同的服务相比是微不足道,价值不高的.由于集群的复杂性,每个应用服务器都以统一的方法实现群集组件.你应当理解提供商如何实现entity beans, stateless session beans, stateful session beans, 和JMS的群集和失败转移.许多提供商声称支持群集组件,但是他们所做的定义通常意味着涉及集群里运行的组件.例如,BEA WebLogic Server 5.1支持群集stateful session beans但是如果bean实例所在的服务器失败,bean的所有状态都将丢失.客户端然后将必须重新创建和重新驻留,在集群里这么做是没用的.直到BEA WebLogic 6.0, stateful session beans才使用内存复制来处理失败转移和群集.
所有的应用服务器都支持EJB群集,但是在可配置的自动失败转移方面存在着非常大的差别.实际上,一些应用服务器依靠EJB客户端的一些条件,不支持自动的失败转移.例如, Sybase Enterprise Application Server通过你从数据库或者系列化装载bean的状态来支持stateful session bean失败转移.就象上面提到的那样, BEA WebLogic 6.0通过stateful session bean状态的内存复制支持stateful session bean的失败转移.大多数应用服务器可以在集群里运行JMS,但是不具有个别命名的主题(Topics)和队列(Queues)负载均衡或失败转移,记住,你可能需要购买一个JMS的可群集实现.比如说通过购买SonicMQ获得Topics和Queues的负载均衡.
现在,我们转到另外一个重要考虑的事情: HttpSession失败转移.
HttpSession失败转移
当客户端在原始的服务器上建立的一个session失败时,HttpSession失败转移允许客户端从集群里的其他服务器无缝的取得session信息. BEA WebLogic Server实现了session信息的内存复制,而HP Bluestone Total-e-Server有个为HA所做的备份,利用了一个中央集中session服务器. SilverStream Application Server和Sybase Enterprise Application Server利用一个所有应用服务器都要读写的中央集中数据库或者文件系统.
数据库/文件系统session持久性的主要缺点集中在当存储大的或者众多的HttpSession对象时受限的伸缩性.一个用户每次增加一个对象到HttpSession,在session里的所有对象都被系列化写到一个数据库或者共享文件系统.大多数利用了数据库session持久性的应用服务器提倡最小限度的使用HttpSession存储对象,但是这限制了你web应用的架构和设计,尤其如果你正在使用HttpSession来存储缓存的用户数据.
基于内存的session持久性把内存里的session信息存储到备份服务器.这种方法存在两种变化.第一个方法把HttpSession信息写到一个中央集中的状态服务器.集群里的所有机器把它们的HttpSession对象写到这个服务器.在第二种方法里,每个集群节点选择一个任意备份节点来存储内存里的session信息.用户每次增加一个对象到HttpSession,那个对象独自被序列化,然后从内存里添加到一个备份服务器.
在这些方法中,如果集群里的服务器数低的话,这个专门的状态服务器证明了比内存复制到一个任意的备份服务器更好,因为为了事务处理和动态页面生成,它释放了CPU周期.
另一方面,当集群里的机器数变大时,这个专门的状态服务器会成为瓶颈,当你增加更多的服务器时,内存复制到一个任意的备份服务器(相对于一个专门的状态服务器来说)将线形伸缩.此外,当你在集群里增加更多的机器时,也需要你增加更多的RAM和CPUs来持续的调整这个状态服务器.对于内存复制到一个任意的备份服务器来说,你只需添加更多的机器,sessions可以均匀的把自己分布到集群里的所有机器上.
基于内存的持久性提供了柔性的web应用设计,伸缩性和高可用性.
我们已经解决了HttpSession的失败转移, 现在我们将研究单点失败(single points of failure)
单点失败(single points of failure)
没有备份的集群服务以单点失败而闻名.他们会引起整个集群或你的部分应用失败.例如, WebLogic JMS可以在集群里的单机上只有一个运行的Topic. 你的应用依赖JMS Topics,如果那台机器发生死机,你的集群将down掉直到另外一个WebLogic实例和那个JMS Topics一起启动. (注意:当开始新的实例时, 只有持久信息将被发送.)
问问自己你的集群是否具有单点失败,如果有的话,你需要估计基于你应用的需求,是否可以忍受它们.
下面,开始说明柔性伸缩拓扑.
本文地址:http://com.8s8s.com/it/it18091.htm