web层集群是J2EE集群中最重要和基础的功能。web层集群技术包括:Web负载均衡和HTTPSession失效转移。
web负载均衡
J2EE提供商有很多方法实现web负载均衡,基本的,在浏览器和web服务器之间放置负载均衡器。
图5:web负载均衡
负载均衡器可以是硬件产品如F5 负载均衡器,也可以是另一个带有负载均衡插件的web服务器。简单的带有ipchains的Linux box也可以执行负载均衡的功能。无论何种技术,负载均衡器通常有以下特性:
*实现负载均衡算法
当客户端请求达到时,负载均衡器决定如何分发请求到后端服务器实例。通常的算法包括Round-Robin,(指的是使组中所有成员都能均等地以某种合理 的顺序被选择到的一种安排方式, 通常是从列表的头至尾,而后周而复始),随机和基于权重。 负载均衡器试图使每个服务器实例完成相同的工作量,但以上算法都不能真正达到理想的等量,因为他们只是基于分发到某个服务器实例请求的数量来计算。一些聪 明的负载均衡器实现特别的算法,他们会测试每个服务器的工作负载来决定分发请求。
*心跳检测
当一些服务器实例失效时,负载均衡器应该检测到失效,并不再分发请求到失效的服务器上。负载均衡器也需要监视服务器恢复状况,并给它重新分发请求。
*会话粘连
几乎每个web应用都有会话状态,使得记住用户是否登陆或购物车变得非常简单。因为HTTP协议本身没有状态,会话状态需要存在某个地方,并和浏览会话关 联起来,可以在下一次请求时很容易地被检索到。当负载均衡时,最好选择分发相同的浏览器会话请求到同一台服务器实例上,否则应用工作会不正常。
因为会话状态存储在某个web服务器实例的内存中,“会话粘连”对于负载均衡非常重要。但,如果一台服务器实例因为某些原因失效(比如断电),那么该服务 器上多有的会话状态就丢失了。负载均衡器检测到了该失效,不再向其分发请求。但存储在失效服务器上的会话的那些请求将丢失会话信息,这种情况会引起错误, 因此会话失效转移到来了!
4.2 HTTPSession失效转移
几乎所有的流行的J2EE提供商都在他们的集群产品中实现了HTTPSession失效转移,确保所有的客户请求可以不因为一些服务器实例的失效而丢失任 何会话状态。如图6所示,当浏览器访问一个有状态的web应用(第1,2步),此应用可以在内存中创建会话对象存储信息以备后用。同时,向浏览器送回 HTTPSession ID,用来标记该会话对象(第3步)。浏览器以cookie的方式存储该ID,并会在下次发起请求时送回web服务器。为了支持会话失效转移,会话对象将 在某时某处将它自己备份(第4步)。负载均衡器可以检测失效(第5,6步),分发请求到其他服务器实例(第7步)。因为会话对象已经被备份,新的web服 务器实例可以恢复该会话并正确地处理请求。
图6:HTTPSession失效转移
为了实现以上功能,注意下列问题:
*全局HTTPSession ID
如上所述,HTTPSession ID用来标记某个服务器实例内存中的会话对象。在J2EE中,HTTPSession ID依赖于JVM实例。每个JVM实例可以控制多个web应用,每个应用又可以控制许多不同用户的HTTPSession,HTTPSession ID是存取当前JVM实例中相关会话对象的键。在会话失效转移实现中,要求不同的JVM实例不应该产生两个同样的HTTPSession ID,因为失效时,在一个JVM的会话可能在另一个JVM中备份和恢复。所以,应该建立全局的HTTPSession ID机制。
*如何备份会话状态
如何备份会话状态是一个使得J2EE服务器与众不同的关键因素。不同的提供商实现不同。
*备份频率和粒度
HTTPSession状态备份有性能消耗,包括CPU周期,网络带宽和写磁盘和数据库的IO消耗。备份频率和粒度严重影响集群的性能。
4.3 数据库持久化方案
几乎所有的J2EE集群产品允许你通过JDBC接口使用关系数据库备份会话状态。如图7所示,该方案只是简单地让服务器实例序列化会话内容,并在适当的时 候写入数据库。当失效转移发生时,另一个可用的服务器实例负责失效的服务器,并从数据库中恢复会话状态。 对象序列化是关键点,使得内存会话对象数据持久化和可移动。更多对象序列化信息请参考
http://java.sun.com/j2se/1.5.0/docs/guide/serialization/index.html
图7:备份会话状态到数据库
象数据库事务一样代价昂贵,该方案的主要缺点是有限的伸缩性:当存储大量会话中的对象时。许多使用数据库会话持久化的应用服务器鼓吹 HTTPSession的最小限度的使用,但其实他们还限制了你的应用架构和设计,特别是如果你使用HTTPSession存储缓冲用户数据。
数据库方案也有一些优点.
*实现简单。江会话备份处理和请求处理分离,使得集群易于管理并比较健壮。
*会话可以失效转移到任何其它机器上,因为使用共享数据库。
*会话数据可以在整个集群失效后仍然生存。
4.4 内存复制方案
由于性能问题,一些J2EE服务器(Tomcat,JBoss,WebLogic和WebSphere)提供另一种实现:内存复制。
图8:内存复制
基于内存的会话持久化存储会话信息,该方案由于性能好非常流行。和数据库方案比较,在原始服务器和备份服务器之间直接网络通信是非常轻量级的。请注意该方案,数据库方案中的“恢复”阶段是不需要的。请求到来时,所有的会话数据已经存在于备份服务器的内存中了。
”JavaGroups”是目前JBoss和Tomcat集群的通讯层,JavaGroups 是一个实现群通讯和管理的工具包。它提供的核心特性是“Group membership protocols”和“message multicast”更多信息请参考http://www.jgroups.org/javagroupsnew/docs/index.html
4.4.1 Tomcat方案:多机复制
内存复制存在很多变体方案。一中办法是跨集群中的多节点复制会话状态。Tomcat5以此法实现内存复制。
图9:多机复制
如图9所示,当一个服务器实例的会话状态改变时,它将向集群中所有服务器备份它的数据。如果其中一个实例失效,负载均衡器可选择其它任何可用的服务器实例 作为其备份服务器。但该方案在伸缩性上有缺陷。如果集群中有很多实例,网络通讯消耗就不可忽略了,这种情况将严重降低性能和网络交通,成为瓶颈问题。
4.4.2 Weblogic, Jboss and WebSphere的方案--配对复制
因为性能和伸缩性问题,Weblogic, JBoss and Websphere 都提供了另一种方法实现内存复制:每个服务器实例选择任一个备份实例存储会话信息,如图10。
按这种方式,每个服务器实例拥有它自己的配对备份服务器而不是所有其它服务器。该方案消除了伸缩性问题。
图10:配对复制
虽然该方案实现了会话失效转移的高性能和高伸缩性,仍然有下列限制:
*给负载均衡器带来了复杂性。当一台服务器实例失效,负载均衡器必须记住哪个实例是其配对备份服务器,缩小了负载均衡器 的选择范围,一些硬件均衡器不能在此结构中使用。
* 除了处理正常的请求,服务器同时负责复制。每个服务器实例,请求处理容量被减小,因为CPU周期需要完成复制职责。
*除了正常处理,许多内存被用来存储备份会话状态,即使没有失效转移发生,也增加了JVM垃圾收集的消耗。
*集群中的服务器实例组成复制配对。所以如果会话粘连失效的主服务器,负载均衡器能发送失效转移请求到备份服务器上。备份服务器将在进入的请求中遇到麻烦,引起性能问题。
为了克服以上限制,不同的提供商的变种产生了。Weblogic 为每个会话而不是服务器定义了备份配对。当一台服务器实例失效,失效服务器上的会话被分散到不同备份服务器上,并且被分散地装载。
4.4.4 IBM的方案--*状态服务器
Websphere 另一个可用的内存复制选择是:备份会话信息到一个*状态服务器,如图11。
图11:*服务器复制
和数据库方案非常相似,不同的是一个专门的“会话备份服务器”代替了数据库服务器。该方案兼有数据库和内存复制的优点:
*分离的请求处理和会话备份,使得集群更强壮。
*所有的会话数据备份到专门的服务器上。bu需要服务器实例浪费内存区保存其它服务器的备份会话数据。
*会话可以失效转移到其它任何实例上。因为会话备份服务器是被集群中的所有节点共享的。所以,大多数负载均衡软件和硬件可以在此集群中使用。更重要的是,请求装载在失效时将均匀分散。
*因为应用服务器和会话备份服务器之间的socket通讯是轻量级的相对于重型的数据库联接。它比数据库方案有着更好的性能和伸缩性。
然而,由于“恢复”阶段覆盖失效服务器的会话数据,它的性能和直接或配对内存复制方案不一样,附加的会话备份服务器对管理员也增加了复杂性,性能瓶颈由备份服务器自己的性能所限制。
4.4.5 Sun的方案--特殊的数据库
图12
Sun JES应用服务器采用了别的方式实现会话失效转移,如图12所示,它看上去很像数据库的方式,因为它采用关系数据库存储会话并通过JDBC访问所有会话数据。但是JES内部所使用的关系数据库称为HADB,已经为访问会话做了特别优化,并且将几乎所有的会话数据存在内存中。这样,你可以说它更像*状态服务器的方式。
性能因素
考虑如下问题:
一台WEB服务器中可能运行着许多WEB应用,它们中每一个都可能被成百的并发用户访问,而每个用户都会产生浏览器会话用于访问特定的应用。所有会话信息都将备份以便服务器失效后能转移到其他服务器实例中。更糟的是,会话会由于一次次的发生以下情况而变化,包括创建、失效、增加属性、删除属性、修改属性值。甚至是什么都没变,但由于有新的访问而使最后访问时间变了(由此判断什么时候失效会话)。因此,性能在会话失效转移的解决方案中是个很大的因素。供应商通常会提供一些可调的参数改变服务器行为,使之适应性能需求。
备份时机
当客户端的请求被处理后,会话随时改变。由于性能因素,实时备份会话是不明智的。选择备份频率需要平衡。如果备份动作发生得太频繁,性能将急剧下降。如果两次备份的间隔太长,那么在这间隔之间服务器失效后,很多会话信息将会丢失。不管所有的方式,包括数据库和内存复制,下面是决定备份频率的常用的选项。
- 按WEB请求
- 按固定的时间间隔
会话在后台按固定的时间间隔保存。这种方式不能保证备份的会话数据是最新的。但由于不需在每次请求之后备份数据,因而有更好的性能。
备份粒度
当备份会话的时候,你还需要决定多少会话状态需要保存。以下是不同产品所有采用的常用的策略。
- 整个会话
每次都将保存所有会话。这种方式为正确保存分布式WEB应用的会话提供了最好保证。这种方式简单,内存复制和数据库存储方式都默认采用这种方式。
- 修改过的会话
当会话被修改过后,则备份整个会话。当“session.setAttribute()”或 “session.removeAttribute()”被调用后,则认为会话被修改过。必须保证这些方法调用才修改会话属性,这并不是J2EE规范后要求的。但却是正确实现这种方法所需要的。备份修改过的会话减少了会话存储的数量,那些仅仅是读取会话属性的请求将不会触发会话备份的动作。这将带来比备份整个会话更好的性能。
- 修改的属性
仅仅是保存被修改过的会话属性而不是整个会话。这将最小化备份的会话数据。这种方式带来最好的性能及最小的网络通信。为了保证这种方式工作的正确性,必须依据以下的要点。首先,只能通过调用“setAttribute()”方法修改会话状态,并且会话数据要被序列化和备份。其次,确保属性之间没有交叉引用。每个唯一的属性键值下的对象图应当被独立地序列化和保存。如果两个独立的键值下的对象存在交叉引用,它们将不能够正确的序列化和反序列化。例如图13所示,在一个内存复制的集群中,会话中存有“student”和“school”对象,同时“school”对象含有到“student”对象的引用,某一个时候“school”被修改后备份到备份服务器中。在序列化和反序列化之后,在备份服务器的被还原的“school”对象的版本将包含整个对象图,包括其引用的“student”对象。但是“student”对象可以被独立的修改,当它被修改后,仅仅只有它自己被备份。在序列化和反序列化之后,在备份服务器中还原“student”对象,但在此时,它将丢失与“school”对象的连接。尽管这种方式有最好的性能,但上述限制将影响WEB应用程序的架构和设计。特别是需要用会话保存缓存的复杂的用户数据。
图 13 会话复制中的交叉引用
其它失效转移的实现
如前面章节所提到的,当会话备份时粒度对于性能非常重要。然而,当前的一些实现,不管是数据库存储还是内存复制,都将使用Java对象序列化技术来传输Java对象。这就打了个大印子,影响系统的性能,并给WEB应用程序的架构和设计带来很多的限制。一些J2EE供应商便寻找一些特别的手段来更为轻量地,小印子地实现WEB集群,提供细粒度的分布式对象共享机制用于提高集群的性能。
Jrun的Jini技术
Jrun4将它的集群解决方案构在Jini技术之上。Jini为分布式计算而生,它允许在一个单一的分布式计算空间内创建“联合”的设备或组件。Jini提供查找,注册,租用等分布式系统服务,这对集群环境非常有用。另一种称为JavaSpace的技术构建于Jini之上,它提供了一些用于实现集群非常有价值的特性,如对象处理,共享,迁移等。要了解有关Jini和JavaSpace更多的信息,请参考http://java.sun.com/products/jini/2_0index.html
Tangosol的分布式缓存
Tangosol Coherence提供了一个分布式数据管理平台,它可以嵌入到大多数流行的J2EE服务器中用于实现集群环境。Tangosol Coherence同时也是提供了分布式缓存系统用于在不同的JVM之间有效地共享Java对象。要了解有关Tangosol更多的信息,请参考http://www.tangosol.com