随着最近项目的推进,一个简单的tomcat已经远远不能满足性能需要了,拼死拼活也就四五百个并发数。在老板还没拍板追加money换商业服务器前,只能继续用免费的东西。还好,tomcat的性能问题已经在网上被炒了很久了,相应的解决方法也有不少,集群就是一个不错的方案,一方面,单个tomcat占用的内存顶多也就两百多M,服务器的硬件还有很大剩余;另一方面,在单个tomcat的基础上增加集群,开发者不必学习太多其他东西,转换曲线比较平滑
集群和负载均衡经常放在一起讨论,具体概念就不说了,其实我也没有专门去研究,简单地认为集群包括负载均衡以及冗余性,就当是磁盘阵列那样,一方面通过并行(负载均衡)提高吞吐量,一方面通过冗余数据(session复制等)提高系统的稳定性安全性,我主要学了一下简单的负载均衡。
言归正传,我是以一个apache作为负载均衡器,将客户端的请求分发到多台tomcat,从而实现简单的负载均衡。apache和tomcat之间的通讯是使用JK连接器,我们可以把它当成一种协议适配器(准确地说是利用AJP进行相互通讯的)。整个系统放在一个工作站上,配置是4核酷睿和4G内存。
首先提供用到的各个组件的下载地址:
apache http server 2.2.6
http://httpd.apache.org/
tomcat 6 压缩版,不使用Windows安装版,后面会解释
http://tomcat.apache.org/download-60.cgi
apache的JK连接器(Windows版本),作为apache的一个module,网站同时提供了配置文件的使用方法
http://tomcat.apache.org/connectors-doc/
1.JK连接器就是一个文件,把后缀名改为so,拷贝到apache的modules目录下
2.修改apache的配置文件 httpd,在最后加上下面这段话:
# 载入jk连接器
LoadModule jk_module modules/mod_jk.so
# 设置负载均衡的配置文件,即定义均衡规则
JkWorkersFile conf/workers.properties
# 指定日志文件
JkLogFile logs/mod_jk.log
# 指定日志级别
JkLogLevel debug
# 日志记录的格式
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
# 配置apache将哪些请求转发给JK进行均衡
JkMount /*.jsp loadbalancer
JkMount /*.do loadbalancer
3.解压缩tomcat,假定第一个tomcat根目录是 d:/tomcat1,修改tomcat1/bin目录下的startup.bat,这是tomcat的启动脚本,在开头的地方加上两行内容:
set CATALINA_HOME="E:\server\Tomcat2"
SET CATALINA_OPTS= -Xms512m -Xmx1024m
第一行的意思是设置当前命令行下tomcat的根目录为 D:/tomcat1,第二行是设置tomcat使用的内存大小:最小256M,最大512M,默认的tomcat内存太小经常在并发数大时造成JVM内存溢出。
4.解释一下为什么加上第一行。如果你的tomcat是Windows的安装版,那么在安装后会将tomcat注册成系统服务,而你要安装第二个tomcat时,会提示无法注册相同的服务。当你使用bin目录下的tomcat6w.exe这个可视化窗口进行配置时,你会发现,修改了第一个tomcat的启动参数后,第二个的也被修改了,这是因为这个tomcat6w.exe修改的是系统服务的参数。同样的,你用tomcat6w.exe启动第二个tomcat时,会报告端口冲突,即便你已经修改了server.xml配置文件,原因也是两个tomcat的启动参数是同一个。因此,为了实现一台机器上安装多个tomcat,最好还是直接用解压缩版的,只需修改一下启动脚本,让每个tomcat启动的根目录都指向自己
5.接下来,拷贝多个tomcat,假定放在tomcat2、tomcat3、tomcat4中,然后修改conf/server.xml文件,有如下几处:
Tomcat1的server.xml
maxThreads="500" cOnnectionTimeout="60000"
enableLookups="false"
redirectPort="8443" />
port="8009" protocol="AJP/1.3" redirectPort="8443" />
Tomcat2的server.xml
maxThreads="500" cOnnectionTimeout="60000"
enableLookups="false"
redirectPort="8443" />
port="8010" protocol="AJP/1.3" redirectPort="8443" />
其他tomcat类似…
主要是让每个tomcat的以上几个port端口都不要冲突,特别是AJP的connector的几个参数,比如maxThreads(最大线程数,也就是最大连接数),默认值是150,我改成了500。由于tomcat是利用AJP和apache通讯的,所以你若是修改Http
connector的maxThreads是没用的,体现不出负载均衡的优势。而Engine标签的jvmRoute属性是作为在负载均衡中的名字,这里依次为worker1,worker2…最后按照第三步修改每个tomcat的
startup.bat文件
# 定义分隔符
ps=\
# 定义负载均衡的所有主机名,和前面tomcat配置文件的JVMroute属性相对应
#其中的loadbalancer是虚拟的主机,负责负载均衡,姑且当成是apache本身
worker.list=worker1,worker2,worker3,worker4,loadbalancer
# worker1使用ajp与JK通讯
worker.worker1.type=ajp13
# worker1的地址为localhost,如果tomcat在其他服务器则输入该服务器的地址
worker.worker1.host=localhost
# ajp端口
worker.worker1.port=8009
# 负载因子,值越大则JK分发到此tomcat的负荷越多
worker.worker1.lbfactor=100
# 若本tomcat因故障不能接受请求,则转移到worker2
worker.worker1.redirect=worker2
worker.worker2.host=localhost
worker.worker2.port=8010
worker.worker2.lbfactor=100
worker.worker3.host=localhost
worker.worker3.port=8011
worker.worker3.lbfactor=100
# Define prefered failover node for worker3
worker.worker3.redirect=worker2
worker.worker4.host=localhost
worker.worker4.port=8012
worker.worker4.lbfactor=100
# Define prefered failover node for worker4
worker.worker4.redirect=worker2
worker.loadbalancer.type=lb
# 定义loadbalancer 进行负载均衡的对象
worker.loadbalancer.balanced_workers=worker1,worker2,worker3,worker4
7.将web应用复制到每个tomcat,运行apache,再运行全部tomcat。不使用tomcat的8080端口访问,而是使用默认的80端口,这样请求会首先到达apache,再转发给tomcat。在浏览器中查看源文件,可以发现链接的地址已被apache重写,后面加了一个worker某某字样,便于JK记录负载均衡的目的服务器
6.回到apache那里,在conf/workers.property文件中输入以下内容:
# 定义loadbalancer类型为“负载均衡器(lb)”