通过 Terracotta实现基于Tomcat的Web应用集群
本文介绍如何配置Tomcat和Terracotta服务器将普通的Web应用部署到集群中,实现跨Tomcat节点的session复制,以达到负载均衡、提高系统吞吐量和灾难恢复的效果。
基本原理简介
一般利用Tomcat搭建Web应用集群有如下几种方法:
1、利用负载均衡器的粘session的方式把所有同一session的请求都发送到相同的Tomcat节点。这样不同用户的请求就被平均分配到集群中各个tomcat节点上,实现负载均衡的能力。这样做的缺点是没有灾难恢复的能力。一旦一个节点发生故障,这个节点上所有的session信息全部丢失;
2、利用Tomcatsession复制的机制使得所有session在所有Tomcat节点中保持一致。当一个节点修改一个session数据的时候,该节点会把这个session的所有内容序列化,然后广播给所有其它节点。这样当下一个用户请求被负载均衡器分配到另外一个节点的时候,那个节点上有完备的session信息可以用来服务该请求。这种做法的问题是对session哪怕有一点点修改,也要把整个sessions数据全部序列化(serialize),还要广播给集群中所有节点,不管该节点到底需不需要这个session。这样很容易会造成大量的网络通信,导致网络阻塞。一般采用这种方式,当Tomcat节点超过4个时候,整个集群的吞吐量就不能再上升了;
3、第三种方式是通过cookie保存用户信息的一个或几个关键字,每一个http请求到达web应用的时候,web程序拿这个关键字到数据库中读取相关的数据,然后对其进行处理。也就是说把session数据保存到了数据库中。这样以来在内存中的session就完全不需要了。这样做的缺点就是加大了数据库的负载,使得数据库变成了集群的瓶颈。而通过构造数据库集群提高负载能力往往需要高额的成本。
Terracotta的基本原理是对于集群间共享的数据,当在一个节点发生变化的时候,Terracotta只把变化的部分发送给Terracotta服务器,然后由服务器把它转发给真正需要这个数据的节点。这样对网络的压力就非常小,各个节点也不必浪费CPU时间和内存进行大量的序列化操作。把这种集群间数据共享的机制应用在session同步上,相当于对tomcat第二种集群实现机制进行了优化,既避免了对数据库的依赖,又能达到负载均衡和灾难恢复的效果。在对比测试中,采用Terracotta搭建Tomcat集群,节点达到8个时候,整个集群的吞吐量还一直是线性增长的。
为了方便使用Terracotta搭建Tomcat集群,Terracotta提供了专门的插件tim-tomcat。下面将对集群的搭建进行详细描述。
准备工作
首先需要下载如下软件:
ApacheTomcat
目前Terracotta官方支持的Tomcat版本为:
ApacheTomcat6.0.18
ApacheTomcat5.5.26
ApacheTomcat5.0.28
Terracotta3.0或更高版本
安装过程
在所有机器上安装Java
请参考目前支持的软硬件平台
在所有机器上安装Terracotta
选一台机器作为Terracotta服务器
在所有运行Tomcat的机器上也安装Terracotta,他们将称为Terracotta客户端
在应用服务器节点上安装Tomcat
把要部署的Web应用部署在所有Tomcat上
配置过程
下载附件中的tc-config.xml文件,保存到${TERRACOTTA_HOME}/tc-config.xml(Unix上)或者${TERRACOTTA_HOME}/tc-config.xml(Windows上)。
修改web-applications和web-application部分,把要共享session的应用的contex配置上:
<web-applications>
<web-application>my_web_app1</web-application>
<web-application>my_web_app2</web-application>
</web-applications>
您可能还需要修改Terracotta服务器的信息。比如:
<serverhost="192.168.0.100"><!--IPorhostnameofTCserver-->
<dso-port>9510</dso-port>
</server>
把配制好的tc-config.xml文件拷贝到所有机器上。然后在每一台机器上,进入TERRACOTTA_HOME目录,运行:
UNIX/LINUX
bin/tim-get.shupgradetc-config.xml
<Windows
bin/tim-get.batupgradetc-config.xml
配置Tomcat应用服务器
在Tomcat安装目录的bin子目录中创建startupTC.sh(Unix)或startupTC.bat(Windows)文件。其内容为:
UNIX/LINUX
TC_INSTALL_DIR=<本地Terracotta安装目录>
TC_CONFIG_PATH=<本地tc-config.xml的完整文件名>
.$TC_INSTALL_DIR/bin/dso-env.sh-q
exportJAVA_OPTS="$JAVA_OPTS$TC_JAVA_OPTS"
.startup.sh
Windows
setTC_INSTALL_DIR=<本地Terracotta安装目录>
setTC_CONFIG_PATH=<本地tc-config.xml的完整文件名>
call%TC_INSTALL_DIR%/bin/dso-env.bat-q
setJAVA_OPTS=%JAVA_OPTS%%TC_JAVA_OPTS%
startup.bat
启动集群
在Terracotta服务器上的Terracotta安装目录执行如下命令:
UNIX/LINUX
bin/start-tc-server.sh&
Windows
bin/start-tc-server.bat
在每一台Web应用服务器上的Tomcat安装目录的bin子目录下执行:
UNIX/LINUX
./startupTC.sh
Windows
startupTC.bat
等Tomcat启动以后,查看Tomcat日志文件,确认Terrocotta已经启动。比如在Mac环境中,使用Terracotta3.0.1,看到的日志将包括如下内容:
2009-07-1710:57:39,425INFO-Terracotta3.0.1,asof20090514-130552([email protected])
2009-07-1710:57:39,828INFO-Configurationloadedfromthefileat'/Users/lma/tc-config.xml'.
2009-07-1710:57:39,975INFO-Logfile:'/Users/lma/apps/tomcat-5.5.27/bin/logs/client-logs/terracotta-client.log'.
2009-07-1710:57:42,312INFO-Connectionsuccessfullyestablishedtoserverat192.168.0.102:9510
如果能看到上述信息,说明Terracotta和Tomcat都正常启动,并且已经与Terracotta服务器成功建立了连接。
验证Session集群
集群启动后,我们可以利用Tomcat内置的Web应用examples来验证集群是否成功配置好。
比如有两台Tomcat服务器分别为http://192.168.0.101:8080和http://192.168.0.102:8080。
首先启动dev-concole.sh(Unix)或dev-console.bat(Windows),连接到Terracotta服务器上。您可以看到所有Tomcat节点都显示在ConnectedClients中。另外在ObjectBrowser中可以看到一个共享数据:
tc:session_localhost/examples
说明所有session已经被共享到Terracotta服务器上了。
下面把浏览器指向:
http://localhost:8088/examples/jsp/cal/login.html
输入姓名和EMail。点击Submit进入下一级页面。
这时您可能会看到服务器抛出com.tc.exception.TCNonPortableObjectError异常。仔细查看异常信息会发现原来该例子程序所需的一些类没有包含在tc-config.xml的instrumented-classes配置中。因此需要打开tc-config.xml配置文件,把如下配置添加到<application><dso>中:
<instrumented-classes>
<include>
<class-expression>cal.*</class-expression>
</include>
</instrumented-classes>
重新启动Tomcat。再打开前面的页面。
您可能还会遇见TCNonPortableObjectError,不过这次的错误是有关bootjar的:
com.tc.exception.TCNonPortableObjectError:
*******************************************************************************
Attempttoshareaninstanceofanon-portableclassreferencedbyaportableclass.ThisunshareableclassmustbeintheDSObootjar.ItalsohassuperclasseswhichmustbeintheDSObootjar.Pleaseaddalloftheseclassestothebootjarconfigurationandre-createtheDSObootjar.
只要认真阅读错误信息,按照提示的方法配置tc-config.xml文件,然后执行下面的命令重新生成bootjar文件,再重新启动Tomcat就可以了:
$TERRACOTTA_HOME/bin/make-boot-jar.sh-f$TOMCAT_HOME/tc-config.xml
处理完上述问题后,例子程序中会显示一个日历管理系统。您可以在里面配置一天的工作日程。
在第一台Tomcat服务器上配置好一天的日程,然后到第二台服务器上,打开相同的页面,您会看到前面输入的日程已经显示出来了。您还可以试着在第二台服务器上对日程进行修改,再到第一台上面刷新页面,前面的修改也会立即显示出来。这说明两台Tomcat服务器的session信息已经完全同步了。
错误处理
1.如果启动失败,有可能是JAVA_OPTS没有配置好。
可以尝试在startupTC文件中,在setJAVA_OPTS后面打印出JAVA_OPTS的内容。应该看到类似下面的内容:
-Xmx512m-Xms512M-Xbootclasspath/p:/Users/lma/terracotta/terracotta-3.0.1/lib/dso-boot/dso-boot-hotspot_osx_150_19.jar-Dtc.install-root=/Users/lma/terracotta/terracotta-3.0.1-Dtc.config=/Users/lma/tc-config.xml
2.如果遇见TCNonPortableObjectException异常,说明在Session中共享的类没有包含在tc-config.xml的instrumented-classes配置中。一般在异常新吸力面Terracotta会包含需要添加到配置文件中的信息,比如:
<instrumented-classes>
<include>
<class-expression>num.NumberGuessBean</class-expression>
</include>
<instrumented-classes>
</instrumented-classes>
只要按照提示把配置信息放到tc-config.xml文件中,然会从新启动Tomcat即可。
附件-tc-config.xml
<tc:tc-configxmlns:tc="http://www.terracotta.org/config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.terracotta.org/schema/terracotta-4.xsd">
<servers>
<!--FormoreinformationonworkingwiththeTerracottaconfigurationfile,includinghowtoadd
moreservers,seehttp://www.terracotta.org/web/display/docs/About+Terracotta+Configuration+Files.
Editthefollowingserverelementsothatitshostattributecontainsthevaluematchingthe
hostnamefortheTerracottaserver.-->
<serverhost="localhost">
<dso-port>9510</dso-port>
</server>
<update-check>
<enabled>true</enabled>
</update-check>
</servers>
<!--CheckthattheTIMshowninthe<module>element'snameattributematchestheTomcatversionyou
areusing.TheTIMlistedhere,"tim-tomcat-5.5"isforTomcat5.5.Forexample,ifyouareusing
Tomcat6.0,editthenameto"tim-tomcat-6.0".-->
<clients>
<modules>
<modulename="tim-tomcat-6.0"version="1.1.0"/>
</modules>
</clients>
<!--Using<web-application>elements,enterthecontextrootofthewebapplicationbeingclustered.
Ifyouareclusteringmorethanonewebapplication,useone<web-application>elementperapplication.
Twoexample<web-application>elementsareshownbelow.Editorremovetheseelementsasneeded.
Tosetthevalueofthe<web-application>elementtothedefaultweb-applicationcontext,usethe
specialvalue"ROOT"(withoutquotationmarks).-->
<application>
<dso>
<instrumented-classes>
<include>
<class-expression>num.NumberGuessBean</class-expression>
</include>
<include>
<class-expression>cal.*</class-expression>
</include>
</instrumented-classes>
<web-applications>
<web-application>examples</web-application>
</web-applications>
</dso>
</application>
</tc:tc-config>