4 WEB层集群实现
WEB层集群是J2EE集群的重要且基本的功能。WEB集群技术包括WEB负载均衡和HTTP Session失效转移。
4.1 WEB负载均衡
J2EE提供商实现WEB负载均衡有许多方式。基本上,都一个负载均衡器被插入到浏览器和WEB服务器之间,如下图所示。
图 5 WEB负载均衡
负载均衡器可以是一台硬件,如F5负载均衡器,或仅仅是另一台有负载均衡Plug-Ins的WEB服务器,一个简单的带ipchains的Linux box可以很好的实现负载均衡。不管采用哪种技术,负载均衡器都有以下特性:
4.1.1 实现负载均衡算法
当客户请求到来时,负载均衡器需要决定将如何分发到后台服务器。流行的算法是Round-Robin、Random和Weight Based。负载均衡器尽力使每台服务器实例都获得相同的负载,但是上述算法没有一个可以获得理想的负载相同,因为它们仅仅是依据发送到特定服务器的请求的个数。一些精密的负载均衡器实现了特殊的算法。它在分发请求之前将检测服务器的工作负载。
- 健康检测
当一台服务器失效了,负载均衡器应当检测出失效并不再将请求分发到这台服务器上。同样,它也要检测服务器是否恢复正常,并恢复分发请求。
- 会话胶粘
几乎所有的WEB应用程序都有一些会话状态,可能是简单的记住用户是否登陆,或是包含你的购物车信息。因为HTTP本身是无状态的,会话状态应当存在服务器的某个地方并与你当前浏览会话相关联,这样当你下次再请求相同WEB应用程序的页面时可以很容易的重新获取。当负载均衡时,最佳的选择就是将特定的浏览器会话分发到上次相同的服务器实例中,否则,应用程序可能不能正确工作。
因为会话状态存储在特定WEB服务器的内存中,“会话胶粘”对于负荷均衡非常重要。但是,如果其中某台服务器实例因为某种原因失效了(比如关机),那么这台服务器的会话状态将要丢失。负载均衡器应当检测到这个失效并不再将请求分发给它,但这些请求的会话状态都因为存放在失效的服务器中而丢失了所有信息,这就将导致错误。会话的失效转移因此而生。
4.2 HTTP Session失效转移
几乎所有流行的J2EE供应商都在他们的集群产品中实现了Http Session失效转移,用来保障当某台服务器失效后会话状态不会丢失,使客户端请求能被正确处理。如图6所示,当浏览器访问有状态的WEB应用程序(第1 ,2步),这个应用程序可能在内存创建了会话对象用于保存信息以供后面的请求使用,同时,发送给浏览器一个唯一的HTTP Session ID用于标识这个会话对象(第3步),浏览器将这个ID保存Cookie中,并当它下次再请求同一WEB应用程序的页面时,会将Cookie发还给服务器。为了支持会话失效转移,WEB服务器将在一定的时候把会话对象备份到其他地方以防止服务器失效后丢失会话信息(第4步)。负载均衡器检测到这个失败(第5,6步),并将后续的请求分发到装有相同应用程序的服务器实例中(第7步),由于会话对象已经备份到其他地方了,这个新的服务器实例可以恢复会话(第8步)正确地处理请求。
图 6 HTTP Session失效转移
为了实现上述功能,HTTP Session失效转移将带来以下问题:
- 全局HTTP Session ID
如上所述,HTTP Session ID用于在特定的服务器实例中标识唯一的内存会话对象,在J2EE平台,HTTP Session ID依赖于JVM实例,每个JVM实例拥有几个应用程序,每个应用程序都为不同的用户管着许多会话,HTTP Session ID是在当前JVM实例用于访问相关会话的关键。在会话失效转移的实现中,要求不同的JVM实例不能产生两个相同的HTTP Session ID,这是因为当失效转移发生时,一个JVM的会话将要备份并恢复到另一个中,这样,必须建立全局HTTP Session ID产生机制。
- 如何备份会话状态
如何备份会话状态是区别J2EE服务器好坏的关键因素。不同的供应商有不同的实现,在后续部分我再详细解释。
- 备份的频率和粒度
会话的备份是消耗性能的,包括CPU,内存,网络带宽和写入磁盘和数据库的I/O,备份的频率和备份对象的粒度将严重影响性能。
4.2.1 数据库备份方式
几乎所有的J2EE集群产品都允许选择将你的会话对象通过JDBC备份到关系数据库中。如图7所示,这种方式可以让服务器实例非常简单的在正确的时间序列化会话内容并写到数据库中。当发生会话转移时,另一台可用的服务器接过已失效的服务器工作,从数据库中恢复所有的会话状态。序列化对象是关键点,它使得内存会话数据可以持久化和传输。要了解更多有关Java对象序列化知识,请参考http://java.sun.com/j2se/1.5.0/docs/guide/serialization/index.html。
图 7 备份会话数据到数据库
由于数据库交易是非常昂贵的,这种方法主要缺点是当在会话中保存大量的或大的对象时限制了伸缩性,大多数使用数据库会话持久化的服务器产品都提倡尽量减少用HTTP会话存储对象,但这限制了你的应用程序的架构和设计,特别是你要使用HTTP会话缓存用户数据时。
数据库的方式也有一些优点:
- 简单,容易实现。分离的请求处理和会话备份处理使集群更好管理和健壮。
- 会话可以失效转移到任何一台服务器,因为数据库是共享的。
- 当整个集群失效时,会话数据依旧幸免。
4.2.2 内存复制方式
因为性能的原因,一些J2EE服务器(Tomcat,Jboss,WebLogic,WebSphere)提供了另一种实现:内存复制
图 8 对会话状态进行内存复制
基于内存的会话持久化将会话信息保存在一台或是多台备份服务器中,而不是保存数据库中(如图8)。这种方式因为性能高而非常流行。同数据库方式相比,直接在原服务器和备份服务器之间网络通信是非常轻量的。同时注意在使用方式中,数据库方式中的“恢复”阶段是不需要的,因为在备份后,所有会话数据都已经存在备份服务器的内存中了,已经可以处理请求。
“Java Groups”是当前Tomcat和Jboss集群所使用的通信层。Java Groups是用于实现可靠组通信和管理的工具包。它提供了诸如“组成员协议”和“消息广播”等核心特性,这些都对集群的工作非常有用。有关Java Groups的信息,请参考:http://www.jgroups.org/javagroupsnew/docs/index.html。
4.2.3 Tomcat方式:多服务器复制
内存复制也存在许多不同的方式,第一种方法就是将会话数据复制到集群中的所有结点,Tomcat5采用的就是这种方式。
图9 多服务器复制
如图9所示,当一个服务器实例的会话改变后,将备份到其他所有的服务器上。当一台服务器失效后,负载均衡器可以选择其他任何一台可用的服务器实例。但这种方式限制了伸缩性,如果集群中有很多的服务器实例,那么网络通信的代价就不能被忽略,这将严重降低性能,并且网络也将成为系统的瓶颈。
4.2.4 WebLogic,Jboss和Websphere的方式:对等服务器复制
由于性能和伸缩性的原因,WebLogic,Jboss和Webshpere采用了其他方式实现内存复制。每台服务器任意选择一台服务器备份其内存中的会话信息。如图10所示。
在这种方式中,每台服务器都有一台自己的对等服务器,而不是其他所有的服务器,这种方式消除在集群中加入过多服务器实例的话影响伸缩性的问题。
图 10 对等服务器复制
尽管这种方式实现失效转移有很高的性能和伸缩性,但它仍有一些限制:
- 它给负载均衡器带来了更多的复杂性。当一台服务失效后,负载均衡器必须知道那台服务是这台己失效服务器的对等备份服务器。这将缩小了负载均衡器的选择范围,同时有些硬件也不能满足这种要求。
- 除了处理正常的请求外,服务器还将负责复制的任务。由于备份会话数据的任务也需要占用CPU的周期,所以每台服务器的请求处理能力也降低了。
- 在没有发生失效转移的时候,备份服务器上大量用于备份的内存是个浪费。同时这也将增加了JVM GC的负担。
- 集群中的服务器实例构成了复制对。这样,当会话所在主服务器失效后,负载均衡器将会话转移到备份服务器,使备份服务器处理两倍的请求,这将造成备份服务器的性能问题。
为了克服上面的4点问题,不同的软件供应商采用了不同的方法,WebLogic采用的复制对不是对每台服务器,而是对每个会话。当一台服务器实例失效后,会话数据己经分散备份到多个备份服务器上,使失效的负载均匀地分布。
4.2.5 IBM的方式:中央状态服务器
Websphere采用不同的方式实现内存复制:备份会话信息到中央的状态服务器,如图11所示:
图 11 中央状态服务器复制
这与数据库的解决方案非常类似,不同之处在于专用的“会话备份服务器”代替了数据库服务器,这种方式结合了数据库和内存复制两种方式的优点。
- 将请求处理和会话备份处理分开使用集群更加健壮。
- 所有的会话数据都备份到专用的服务器上,无需服务器浪费内存用于备份其他服务器的会话。
- 因为会话备份服务器是在服务器之间共享的,所有失效后可以转移到任何一台服务器上,这样大多数据软硬件负载均衡器都可以使用,更重要的是当一台服务器失效后,负载将均匀的分布到所有实例上。
- 与重量级的数据库连接相比,应用服务器与备份服务器之间Socket通信是轻量的。这样就比数据库的解决方案有更好的性能和更好的伸缩性。
然而,由于有恢复失效服务器会话数据的这么一个阶段,因此其性能肯定不如两台服务器直接复制解决方案,另外,多出来一台备份服务器也增加了管理的复杂性。也可能由于单台备份服务器造成性能瓶颈。
4.2.6 Sun的方式:特殊数据库
图 12 特殊数据库复制
Sun JES应用服务器采用了别的方式实现会话失效转移,如图12所示,它看上去很像数据库的方式,因为它采用关系数据库存储会话并通过JDBC访问所有会话数据。但是JES内部所使用的关系数据库称为HADB,已经为访问会话做了特别优化,并且将几乎所有的会话数据存在内存中。这样,你可以说它更像中央状态服务器的方式。
4.2.7 性能因素
考虑如下问题:一台WEB服务器中可能运行着许多WEB应用,它们中每一个都可能被成百的并发用户访问,而每个用户都会产生浏览器会话用于访问特定的应用。所有会话信息都将备份以便服务器失效后能转移到其他服务器实例中。更糟的是,会话会由于一次次的发生以下情况而变化,包括创建、失效、增加属性、删除属性、修改属性值。甚至是什么都没变,但由于有新的访问而使最后访问时间变了(由此判断什么时候失效会话)。因此,性能在会话失效转移的解决方案中是个很大的因素。供应商通常会提供一些可调的参数改变服务器行为,使之适应性能需求。
4.2.7.1 备份时机
当客户端的请求被处理后,会话随时改变。由于性能因素,实时备份会话是不明智的。选择备份频率需要平衡。如果备份动作发生得太频繁,性能将急剧下降。如果两次备份的间隔太长,那么在这间隔之间服务器失效后,很多会话信息将会丢失。不管所有的方式,包括数据库和内存复制,下面是决定备份频率的常用的选项。
- 按WEB请求
在WEB请求处理结束后,发生响应之前保存数据。这种方式能够保证在失效后备份的会话数据是最新的。
- 按固定的时间间隔
会话在后台按固定的时间间隔保存。这种方式不能保证备份的会话数据是最新的。但由于不需在每次请求之后备份数据,因而有更好的性能。
4.2.7.2 备份粒度
当备份会话的时候,你还需要决定多少会话状态需要保存。以下是不同产品所有采用的常用的策略。
- 整个会话
每次都将保存所有会话。这种方式为正确保存分布式WEB应用的会话提供了最好保证。这种方式简单,内存复制和数据库存储方式都默认采用这种方式。
- 修改过的会话
当会话被修改过后,则备份整个会话。当“session.setAttribute()”或 “session.removeAttribute()”被调用后,则认为会话被修改过。必须保证这些方法调用才修改会话属性,这并不是J2EE规范后要求的。但却是正确实现这种方法所需要的。备份修改过的会话减少了会话存储的数量,那些仅仅是读取会话属性的请求将不会触发会话备份的动作。这将带来比备份整个会话更好的性能。
- 修改过的属性
仅仅是保存被修改过的会话属性而不是整个会话。这将最小化备份的会话数据。这种方式带来最好的性能及最小的网络通信。为了保证这种方式工作的正确性,必须依据以下的要点。首先,只能通过调用“setAttribute()”方法修改会话状态,并且会话数据要被序列化和备份。其次,确保属性之间没有交叉引用。每个唯一的属性键值下的对象图应当被独立地序列化和保存。如果两个独立的键值下的对象存在交叉引用,它们将不能够正确的序列化和反序列化。例如图13所示,在一个内存复制的集群中,会话中存有“student”和“school”对象,同时“school”对象含有到“student”对象的引用,某一个时候“school”被修改后备份到备份服务器中。在序列化和反序列化之后,在备份服务器的被还原的“school”对象的版本将包含整个对象图,包括其引用的“student”对象。但是“student”对象可以被独立的修改,当它被修改后,仅仅只有它自己被备份。在序列化和反序列化之后,在备份服务器中还原“student”对象,但在此时,它将丢失与“school”对象的连接。尽管这种方式有最好的性能,但上述限制将影响WEB应用程序的架构和设计。特别是需要用会话保存缓存的复杂的用户数据。
图 13 会话复制中的交叉引用
4.2.8 其他失效转移的实现
如前面章节所提到的,当会话备份时粒度对于性能非常重要。然而,当前的一些实现,不管是数据库存储还是内存复制,都将使用Java对象序列化技术来传输Java对象。这就打了个大印子,影响系统的性能,并给WEB应用程序的架构和设计带来很多的限制。一些J2EE供应商便寻找一些特别的手段来更为轻量地,小印子地实现WEB集群,提供细粒度的分布式对象共享机制用于提高集群的性能。
4.2.8.1 Jrun的Jini技术
Jrun4将它的集群解决方案构在Jini技术之上。Jini为分布式计算而生,它允许在一个单一的分布式计算空间内创建“联合”的设备或组件。Jini提供查找,注册,租用等分布式系统服务,这对集群环境非常有用。另一种称为JavaSpace的技术构建于Jini之上,它提供了一些用于实现集群非常有价值的特性,如对象处理,共享,迁移等。要了解有关Jini和JavaSpace更多的信息,请参考http://java.sun.com/products/jini/2_0index.html
4.2.8.2 Tangosol的分布式缓存
Tangosol Coherence提供了一个分布式数据管理平台,它可以嵌入到大多数流行的J2EE服务器中用于实现集群环境。Tangosol Coherence同时也是提供了分布式缓存系统用于在不同的JVM之间有效地共享Java对象。要了解有关Tangosol更多的信息,请参考http://www.tangosol.com