最近在开发的项目需要承受很高的并发量。综合各种情况,决定使用Apache+Tomcat+JK的方式实现负载均衡,并且作为一个统一的服务还要实现群集(同步Session)。在网上找了很多资料,都是零零散散的,没有一个完整的过程。通过几天的努力,完成了从编译、部署
最近在开发的项目需要承受很高的并发量。综合各种情况,决定使用Apache+Tomcat+JK的方式实现负载均衡,并且作为一个统一的服务还要实现群集(同步Session)。
在网上找了很多资料,都是零零散散的,没有一个完整的过程。通过几天的努力,完成了从编译、部署到配置的整个过程,期间也遇到了一些问题。在接下来的文字中将这些过程记录下来,做个笔记同时也分享给大家。
为了重新演示整个过程,我新搭建了一个服务器,各项参数如下:
CPU:Intel Xeon 5506*2
内存:DDR3 4G*4
主机型号:Dell PowerEdge R710
操作系统:CentOS release 5.7 x86_64版
内核版本:2.6.18
gcc版本:4.1.2
g++版本:4.1.2
java版本:1.6.0_30
[root@lxp2 ~]# cat /etc/redhat-release
CentOS release 5.7 (Final)
[root@lxp2 ~]# uname -a
Linux ku6 2.6.18-274.18.1.el5 #1 SMP Thu Feb 9 12:45:44 EST 2012 x86_64 x86_64 x86_64 GNU/Linux
[root@lxp2 ~]# gcc --version
gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-54)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
[root@lxp2 ~]# g++ --version
g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2-54)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
[root@lxp2 ~]# java -version
java version "1.6.0_30"
Java(TM) SE Runtime Environment (build 1.6.0_30-b12)
Java HotSpot(TM) 64-Bit Server VM (build 20.5-b03, mixed mode)
[root@lxp2 ~]#
gcc、g++和java是必须的,如果运行上述命令提示command not
found,则需要安装。具体安装方法这里不做介绍,请参阅相关文档。
接下来要准备的是apache服务器、tomcat服务器和JK连接器
1.下载apache服务器源码包
apache服务器官方没有发布编译好的linux二进制包,只能通过下载源代码,然后自己编译。因此需要先下载源码。
访问网址http://httpd.apache.org/download.cgi,可以看到apache服务器目前放出的版本信息,推荐使用稳定版的release。
然后选择Unix版源码:
2.下载tomcat服务器源码包
目前tomcat服务器个人还是觉得6.0比较稳定。7.0毕竟是新出的东西,需要一定的生产实践考验才能达到理想的状态。因此这里选择tomcat
6.0。
访问网址http://tomcat.apache.org/download-60.cgi,可以看到目前稳定的版本为6.0.33:
这里强烈建议下载tar.gz格式的压缩包。在Linux下,文件访问有着严格的权限限制。一个文件是否允许以二进制或者脚本的形式执行,完全取决于其是否拥有执行缺陷,这与Windows识别文件后缀名(.exe、.bat)的方式不同。zip格式的压缩包中是不保留文件的权限信息的,而tar.gz格式的压缩包是保存有文件的权限信息的。
3.下载JK连接器源码包
作为apache与tomcat连接的桥梁,JK连接器使用C语言编写,与apache紧密结合,作为模块装载到apache服务器中,通过配置实现与特定的tomcat服务器进行通信,从而实现负载均衡的功能。
访问网址http://tomcat.apache.org/download-connectors.cgi,可以找到最新最稳定的JK连接器版本:
这里还是推荐下载tar.gz格式的源码。原因同上。
4.解压
apache服务器、tomcat服务器和JK连接器都已经下载好了,如下图所示:
然后将这三个包都解压出来:
5.编译apache服务器
首先编译apache服务器。在编译之前需要执行其自带的检测配置脚本。对于不同发行版本的Linux,默认安装的库都有所差别,即便是同一个发行版本,由于用户安装软件的软件不同,也会导致系统内包含的库有所区别。因此apache作为开源服务器,在编译前需要了解系统的库安装情况,某些模块需要依赖于特定的库,如果这些库不存在,配置脚本将自动忽略这些库的编译。经过检测时候会生成合适的MakeFile文件。这里特别提醒一句,如果直接执行配置脚本,是不会编译额外的模块的,我们希望使用额外模块时,需要在运行配置脚本命令后加入参数,让其尽最大可能编译可用的库。关于这方面的介绍可以参阅我的另外一篇文章“Linux下编译apache服务器modules文件夹缺少模块(.so)的问题”(http://blog.csdn.net/chaijunkun/article/details/6977466)。下面进入apache服务器源码目录并执行配置脚本:
[root@lxp2 Downloads]# cd httpd-2.2.21
[root@lxp2 httpd-2.2.21]# ./configure --enable-so --enable-mods-shared=most --with-mpm=worker
加入--with-mpm=worker是修改apache服务器的工作模式。默认模式是prefork。prefork采用预派生子进程方式,用单独的子进程来处理
不同的请求,进程之间彼此独立。相对于prefork,worker是全新的支持多线程和多进程混合模型的MPM(多路处理模块)。由于使用线程来处理,所以可以处理相对海量的请求,而系统资源的开销要小于基于进程的服务器。但是,worker也使用了多进程,每个进程又生成多个线程,以获得基于进程服务器的稳定性。
如果配置过程中出现
configure: error: Cannot use an external APR with the bundled APR-util
这样的错误信息,说明本机没有安装apr运行库,需要下载并安装。访问网址:http://apr.apache.org/download.cgi,下载apr和apr-util:
解压apr和apr-util
[root@lxp2 Downloads]# tar -xf apr-1.4.5.tar.gz
[root@lxp2 Downloads]# tar -xf apr-util-1.3.12.tar.gz
进入apr,并编译
[root@lxp2 Downloads]# cd apr-1.4.5
[root@lxp2 apr-1.4.5]# ls
apr-config.in build.conf helpers memory shmem
apr.dep build-outputs.mk include misc strings
apr.dsp CHANGES libapr.dep mmap support
apr.dsw config.layout libapr.dsp network_io tables
apr.mak configure libapr.mak NOTICE test
apr.pc.in configure.in libapr.rc NWGNUmakefile threadproc
apr.spec docs LICENSE passwd time
atomic dso locks poll user
build emacs-mode Makefile.in random
buildconf file_io Makefile.win README
[root@lxp2 apr-1.4.5]# ./configure
生成了MakeFile后直接编译
[root@lxp2 apr-1.4.5]# ls
apr-1-config buildconf dso locks poll
apr-config.in build.conf emacs-mode Makefile random
apr.dep build-outputs.mk file_io Makefile.in README
apr.dsp CHANGES helpers Makefile.win shmem
apr.dsw config.layout include memory strings
apr.mak config.log libapr.dep misc support
apr.pc config.nice libapr.dsp mmap tables
apr.pc.in config.status libapr.mak network_io test
apr.spec configure libapr.rc NOTICE threadproc
atomic configure.in libtool NWGNUmakefile time
build docs LICENSE passwd user
[root@lxp2 apr-1.4.5]# make
编译好之后使用root权限安装:
[root@lxp2 apr-1.4.5]# sudo make install
然后使用类似的方法配置apr-util:
[root@lxp2 Downloads]# cd apr-util-1.3.12
[root@lxp2 apr-util-1.3.12]# ./configure --with-apr=/usr/local/apr
编译apr-util:
[root@lxp2 apr-util-1.3.12]# make
编译好之后使用root权限安装:
[root@lxp2 apr-util-1.3.12]# sudo make install
当然如果你在配置apache服务器编译的时候没有提示缺少“APR”,请忽略上面关于APR编译的几步。
回到apache服务器源码所在目录,开始编译:
[root@lxp2 httpd-2.2.21]# make
编译过程大概不到十分钟,完成之后使用root权限进行安装
[root@lxp2 httpd-2.2.21]# sudo make install
如果不出意外,至此apache就安装成功了。来测试一下:
进入apache服务器的bin目录,并启动服务器:
[root@lxp2 httpd-2.2.21]# cd /usr/local/apache2/bin/
[root@lxp2 bin]# sudo ./apachectl start
httpd: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1 for ServerName
在本地打开浏览器,访问http://127.0.0.1
如果出现“It Works!”则表示启动成功了
这里要注意一点就是Linux的防火墙问题。如果你的Linux服务器启动了防火墙,本地访问上面的网址是没有问题的,但如果其它计算机访问你的服务器有可能会连接失败。
出现这种情况的原因是防火墙将入站80端口封锁了。解决方法是将80端口加入到允许列表中:
进入防火墙设置后,如果发现Firewall状态为Enabled,表示防火墙已启用,需要将WWW(HTTP)服务标记为信任,如果需要使用hhtps协议,还要将Secure
WWW(HTTPS)服务也标记为信任。如下图所示:
另外,此时如果有其他程序占用80端口也是会影响到apache服务器的,需要确保这个端口没有被占用。
还有我还要补充一点,在Mac OS中按照上述方法安装apache服务器是不行的。开始的时候我不想搭建Linux服务器,想到Mac
OS也是类Unix的系统,操作命令什么的都一样,就先在Mac上实验了。结果安装上apache服务器后启动了,每次访问都提示505错误,service
temporarily
unavailable。经过查阅很多资料和尝试才发现,原来Mac系统中已经自带了apache服务器。具体应用是在“系统设置”中的“共享”功能。这个功能里有“Web共享”方式。其实现时使用的服务器就是apache。它采用的配置文件在/etc/httpd/目录中。这里的配置文件和自己安装的apache服务器配置文件冲突了,因此造成505错误。这一点需要注意。(注:我是用的Mac系统为Mac
OS X Lion 10.7.2)
2011年11月23日补充:
如果你希望把apache服务器注册为系统服务,让它随着系统启动而启动,则需要在/etc/init.d/目录中建立服务管理脚本,我们将其命名为httpd:
#!/bin/bash
#chkconfig: 345 61 61
#description: This is apache http service
#processname: httpd
pidfile="/usr/local/apache2/logs/httpd.pid"
httpd_process_name="httpd"
httpd_path="/usr/local/apache2/bin/apachectl"
RETVAL=0
start(){
echo "Starting Apache Httpd Service..."
httpd_pid_list=`pidof $httpd_process_name`
if test -n "$httpd_pid_list"
then
echo "Fail To Launch Httpd, Since It Has Already Started"
RETVAL=1
else
echo "Launching Apache Httpd Server"
`$httpd_path "start"`
RETVAL=$?
echo "Launch Httpd Successfully"
fi;
}
stop(){
echo "Stopping Apache Httpd Service..."
httpd_pid_list=`pidof $httpd_process_name`
if test -n "$httpd_pid_list"
then
echo "Find Httpd Process, Start To End Them"
`$httpd_path "stop"`
if test "$?" = "0"
then
echo "Success to Terminate Httpd Service"
RETVAL=0
else
echo "Can Not Terminate Httpd Service"
RETVAL=1
fi;
else
echo "Can Not Find Any Httpd Process, Fail To Stop Service"
RETVAL=0
fi;
}
restart(){
stop
if test "$?"="0"
then
#sleep 3 seconds to wait for process exit
sleep 3
start
RETVAL= $?
else
RETVAL= $?
fi;
}
status(){
if test -f $pidfile
then
pid_list=`cat $pidfile`
echo "$httpd_process_name (pid:$pid_list) is running"
else
echo "$httpd_process_name is stopped"
fi;
}
case "$1" in
start)
start
RETVAL=$?
;;
stop)
stop
RETVAL=$?
;;
restart)
restart
RETVAL=$?
;;
status)
status
;;
*)
echo {1}quot;Usage:$0 {start|stop|restart} asdfasdfasdfasdf "
RETVAL=2
esac
exit $RETVAL
编写完成后保存并赋予755权限。然后在该目录下执行
[root@lxp2 init.d]# chkconfig --add httpd
将服务添加到系统。脚本的具体解释请参阅我的另外一篇博文:
Linux中将memcached注册为系统服务(地址:http://blog.csdn.net/chaijunkun/article/details/7000600)。
6.编译JK连接器
刚刚完成了apache服务器的编译,接下来顺便把JK连接器也编译出来。
进入刚刚解压出来的tomcat-connector目录,再进入native目录。执行配置:
[root@lxp2 Downloads]# cd tomcat-connectors-1.2.32-src
[root@lxp2 tomcat-connectors-1.2.32-src]# ls
BUILD.txt conf docs jkstatus LICENSE native NOTICE support tools xdocs
[root@lxp2 tomcat-connectors-1.2.32-src]# cd native/
[root@lxp2 native]# ls
aclocal.m4 BUILDING.txt configure.in Makefile.am nt_service TODO.txt
apache-1.3 CHANGES docs Makefile.in README.txt
apache-2.0 common iis netscape scripts
buildconf.sh configure jni NEWS STATUS.txt
[root@lxp2 native]# ./configure --with-apxs=/usr/local/apache2/bin/apxs
这里需要注意的是配置脚本要添加一个apxs完整路径作为参数。apxs是一个为Apache
HTTP服务器编译和安装扩展模块的工具,用于编译一个或多个源程序或目标代码文件为动态共享对象,使之可以用由mod_so提供的LoadModule指令在运行时加载到Apache服务器中。
另外,配置脚本运行时会检查g++所在的目录,如果没有安装g++,则会显示:
configure: error: C++ preprocessor "/lib/cpp" fails sanity check
请检查是否已经正确安装了c++编译器。
因为实验用的服务器安装的是X86_64版的Red Hat Enterprise Linux Server
,因此要安装如下的包:
libstdc++-devel-4.1.2-46.el5.x86_64.rpm
gcc-c++-4.1.2-46.el5.x86_64.rpm
如果使用rpm命令无法安装,可以在http://szmov.net/centos5464/CentOS/里查找到相应的资源,下载下来安装也是一样的。
配置无误后就可以编译了,执行make命令:
[root@lxp2 native]# make
7.JK连接器模块的部署
编译完成后使用ls命令来列出native目录下的所有目录和文件。注意有apache-1.3和apache-2.0两个目录。由于在配置编译的时候指定了apxs工具的位置。配置脚本会根据apxs的反馈结果自动识别目标apache服务器为2.x版本,因此本次编译生成的mod_jk.so模块会放在apache-2.0目录中,apache-1.3目录中是没有mod_jk.so的,这一点请注意。如下所示:
[root@lxp2 native]# ls
aclocal.m4 CHANGES configure libtool NEWS TODO.txt
apache-1.3 common configure.in Makefile nt_service
apache-2.0 config.log docs Makefile.am README.txt
buildconf.sh config.nice iis Makefile.in scripts
BUILDING.txt config.status jni netscape STATUS.txt
[root@lxp2 native]# cd apache-2.0/
[root@lxp2 apache-2.0]# ls
bldjk54.qclsrc Makefile.apxs mod_jk.a mod_jk.lo
bldjk.qclsrc Makefile.apxs.in mod_jk.c mod_jk.o
config.m4 Makefile.in mod_jk.dsp mod_jk.so
Makefile Makefile.vc mod_jk.la NWGNUmakefile
[root@lxp2 apache-2.0]#
我们现在将编译好的mod_jk.so拷贝到apache服务器的modules目录中,这个目录是专门用来存放扩展模块的:
[root@lxp2 apache-2.0]# sudo cp ./mod_jk.so /usr/local/apache2/modules/
[root@lxp2 apache-2.0]# cd /usr/local/apache2/modules/
[root@lxp2 modules]# ls
httpd.exp mod_authz_user.so mod_include.so
mod_actions.so mod_autoindex.so mod_info.so
mod_alias.so mod_cgi.so mod_jk.so
mod_asis.so mod_dav_fs.so mod_log_config.so
mod_auth_basic.so mod_dav.so mod_logio.so
mod_auth_digest.so mod_dbd.so mod_mime.so
mod_authn_anon.so mod_deflate.so mod_negotiation.so
mod_authn_dbd.so mod_dir.so mod_reqtimeout.so
mod_authn_dbm.so mod_dumpio.so mod_rewrite.so
mod_authn_default.so mod_env.so mod_setenvif.so
mod_authn_file.so mod_expires.so mod_speling.so
mod_authz_dbm.so mod_ext_filter.so mod_status.so
mod_authz_default.so mod_filter.so mod_substitute.so
mod_authz_groupfile.so mod_headers.so mod_userdir.so
mod_authz_host.so mod_ident.so mod_version.so
mod_authz_owner.so mod_imagemap.so mod_vhost_alias.so
至此JK连接器模块就部署完成了,但是还需要配置,具体配置将在下文中详细描述。
8.部署tomcat服务器
由于要在本地开启两个tomcat服务器实例以模拟负载均衡+群集的效果,因此我们需要将之前解压出来的tomcat复制成两份,进入解压时的目录,重命名解压出来的原始目录为tomcat_server_1,然后复制此目录,副本目录名称为tomcat_server_2:
[root@lxp2 ~]# cd Downloads/
[root@lxp2 Downloads]# ls
apache-tomcat-6.0.33 cpp
apache-tomcat-6.0.33.tar httpd-2.2.21.tar
apr-1.4.5 tomcat-connectors-1.2.32-src
apr-1.4.5.tar.gz tomcat-connectors-1.2.32-src.tar
apr-util-1.3.12
apr-util-1.3.12.tar.gz
[root@lxp2 Downloads]# mv apache-tomcat-6.0.33 tomcat_server_1
[root@lxp2 Downloads]# cp -r tomcat_server_1 tomcat_server_2
[root@lxp2 Downloads]# ls
apache-tomcat-6.0.33.tar httpd-2.2.21.tar
apr-1.4.5 tomcat-connectors-1.2.32-src
apr-1.4.5.tar.gz tomcat-connectors-1.2.32-src.tar
apr-util-1.3.12 tomcat_server_1
apr-util-1.3.12.tar.gz tomcat_server_2
httpd-2.2.21
[root@lxp2 Downloads]#
现在测试tomcat_server_1是否能够正常工作。
将我实现写好的一个测试用例下载下来(测试用例基于Spring
3.0编写,已经打成war包),下载地址:http://download.csdn.net/detail/chaijunkun/3815798。下载得到的文件是TestProject.war。将此压缩包放入tomcat_server_1的webapps目录下。然后切换到tomcat_server_1的bin目录下,启动tomcat_server_1:
[root@lxp2 bin]# ./startup.sh
Using CATALINA_BASE: /root/Downloads/tomcat_server_1
Using CATALINA_HOME: /root/Downloads/tomcat_server_1
Using CATALINA_TMPDIR: /root/Downloads/tomcat_server_1/temp
Using JRE_HOME: /usr/java/jdk1.6.0_27
Using CLASSPATH: /root/Downloads/tomcat_server_1/bin/bootstrap.jar
然后在浏览器中访问http://127.0.0.1:8080/TestProject/showInfo.do,如果没什么意外会显示类似于下面的信息:
This message is from Server, RealPath:
/root/Downloads/tomcat_server_1/webapps/TestProject/
Current Session Id:
471D55C942346EC7BB48D07D9437D57E
信息中显示了当前测试用例所在的路径以及当前会话的SessionId。
此处要注意的地方同测试apache服务器是否正常工作时是一样的,需要注意防火墙是否阻塞了tomcat服务器默认采用的8080端口,是否有其他程序占用此端口。
看到没什么问题,我们先吧tomcat_server_1关闭
[root@lxp2 bin]# ./shutdown.sh
Using CATALINA_BASE: /root/Downloads/tomcat_server_1
Using CATALINA_HOME: /root/Downloads/tomcat_server_1
Using CATALINA_TMPDIR: /root/Downloads/tomcat_server_1/temp
Using JRE_HOME: /usr/java/jdk1.6.0_27
Using CLASSPATH: /root/Downloads/tomcat_server_1/bin/bootstrap.jar
9.apache服务器的配置
apache服务器、tomcat服务器和JK连接器都部署完成并能正确执行后就可以开始配置了
用vi或者其它编辑器打开/usr/local/apache2/conf/httpd.conf文件(由于该文件权限属性为rw-r--r--,因此要想修改此文件需要root权限),这就是apache服务器的主配置文件了。
这里我推荐使用图形化的编辑器来编辑它。因为这个文件很多行,如果用文本模式的编辑器编辑个人感觉很繁琐。
在有很多LoadModule语句的地方,末尾追加一行
LoadModule jk_module modules/mod_jk.so
然后在写有的区域追加一行如下配置
JkWorkersFile conf/workers.properties
JkMountFile conf/uriworkermap.properties
JkLogFile logs/mod_jk.log
JkLogLevel warn
下面给出了一个我写的配置。注意配置中有注释的地方。“#”开头的行为注释行。已经去除了原有的配置中的多余注释。
ServerRoot "/usr/local/apache2"
Listen 80
ServerName 0.0.0.0
ServerAdmin chaijunkun@hotmail.com
DocumentRoot "/usr/local/apache2/htdocs"
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authn_dbm_module modules/mod_authn_dbm.so
LoadModule authn_anon_module modules/mod_authn_anon.so
LoadModule authn_dbd_module modules/mod_authn_dbd.so
LoadModule authn_default_module modules/mod_authn_default.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule authz_dbm_module modules/mod_authz_dbm.so
LoadModule authz_owner_module modules/mod_authz_owner.so
LoadModule authz_default_module modules/mod_authz_default.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule auth_digest_module modules/mod_auth_digest.so
LoadModule dbd_module modules/mod_dbd.so
LoadModule dumpio_module modules/mod_dumpio.so
LoadModule reqtimeout_module modules/mod_reqtimeout.so
LoadModule ext_filter_module modules/mod_ext_filter.so
LoadModule include_module modules/mod_include.so
LoadModule filter_module modules/mod_filter.so
LoadModule substitute_module modules/mod_substitute.so
LoadModule deflate_module modules/mod_deflate.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule logio_module modules/mod_logio.so
LoadModule env_module modules/mod_env.so
LoadModule expires_module modules/mod_expires.so
LoadModule headers_module modules/mod_headers.so
LoadModule ident_module modules/mod_ident.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule version_module modules/mod_version.so
LoadModule mime_module modules/mod_mime.so
LoadModule dav_module modules/mod_dav.so
LoadModule status_module modules/mod_status.so
LoadModule autoindex_module modules/mod_autoindex.so
LoadModule asis_module modules/mod_asis.so
LoadModule info_module modules/mod_info.so
LoadModule cgid_module modules/mod_cgid.so
LoadModule dav_fs_module modules/mod_dav_fs.so
LoadModule vhost_alias_module modules/mod_vhost_alias.so
LoadModule negotiation_module modules/mod_negotiation.so
LoadModule dir_module modules/mod_dir.so
LoadModule imagemap_module modules/mod_imagemap.so
LoadModule actions_module modules/mod_actions.so
LoadModule speling_module modules/mod_speling.so
LoadModule userdir_module modules/mod_userdir.so
LoadModule alias_module modules/mod_alias.so
LoadModule rewrite_module modules/mod_rewrite.so
# Load JK Connector Module
LoadModule jk_module modules/mod_jk.so
User daemon
Group daemon
DirectoryIndex index.html
# Load Configure while Loading JK Connector Module
JkWorkersFile conf/workers.properties
JkMountFile conf/uriworkermap.properties
JkLogFile logs/mod_jk.log
JkLogLevel warn
# Apache Server is working in worker mode
StartServers 5
ServerLimit 20
ThreadLimit 200
MaxClients 4000
MinSpareThreads 25
MaxSpareThreads 250
ThreadsPerChild 200
MaxRequestsPerChild 1000
Order allow,deny
Deny from all
Satisfy All
ErrorLog "logs/error_log"
LogLevel warn
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
CustomLog "logs/access_log" common
ScriptAlias /cgi-bin/ "/usr/local/apache2/cgi-bin/"
DefaultType text/plain
TypesConfig "conf/mime.types"
AddType application/x-compress .Z
AddType application/x-gzip .gz .tgz
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
Options FollowSymLinks
Deny from all
Order deny,allow
AllowOverride None
Options FollowSymLinks Indexes
Allow from all
Order allow,deny
AllowOverride None
Options None
Allow from all
Order allow,deny
AllowOverride None
LoadModule表示当apache服务启动时要加载模块
jk_module为模块的别名,后面跟的modules/mod_jk.so就是相对于apache服务器所在目录(/usr/local/apache2/)的模块文件名。
区域表示当apache服务器加载jk_module(在LoadModule指令中指定的模块别名)模块时所做的配置。
其中:
JkWorkersFile
指定负载均衡服务器的配置文件,文件名为相对于apache服务器所在目录的conf/workers.properties文件
JkMountFile
指定那些请求交由负载均衡服务器来处理,那些由apache服务器来处理,配置文件为相对于apache服务器所在目录的conf/uriworkermap.properties文件
JkLogFile 指定JK连接器的日志输出文件,文件为相对于apache服务器所在目录的logs/mod_jk.log文件
JkLogLevel
指定JK连接器输出日志的级别,级别为warn以上的日志将被输出到日志文件中,可选的值级别由低到高分别为:TRACE DEBUG
INFO WARN ERROR FATAL
------------------------------------------------------------------------------------------------------------------------------------------------
区域表示当apache服务器以worker模式工作时使用的配置。
指令说明:
StartServers:设置服务器启动时建立的子进程数量。因为子进程数量动态的取决于负载的轻重,所有一般没有必要调整这个参数。
ServerLimit:服务器允许配置的进程数上限。只有在你需要将MaxClients和ThreadsPerChild设置成需要超过默认值16个子进程的时候才需要使用这个指令。不要将该指令的值设置的比MaxClients
和ThreadsPerChild需要的子进程数量高。修改此指令的值必须完全停止服务后再启动才能生效,以restart方式重启动将不会生效。
ThreadLimit:设置每个子进程可配置的线程数ThreadsPerChild上限,该指令的值应当和ThreadsPerChild可能达到的最大值保持一致。修改此指令的值必须完全停止服务后再启动才能生效,以restart方式重启动将不会生效。
MaxClients:用于伺服客户端请求的最大接入请求数量(最大线程数)。任何超过MaxClients限制的请求都将进入等候队列。默认值是"400",16
(ServerLimit)乘以25(ThreadsPerChild)的结果。因此要增加MaxClients的时候,你必须同时增加
ServerLimit的值。笔者建议将初始值设为(以Mb为单位的最大物理内存/2),然后根据负载情况进行动态调整。比如一台4G内存的机器,那么初始值就是4000/2=2000。
MinSpareThreads:最小空闲线程数,默认值是"75"。这个MPM将基于整个服务器监视空闲线程数。如果服务器中总的空闲线程数太少,子进程将产生新的空闲线程。
MaxSpareThreads:设置最大空闲线程数。默认值是"250"。这个MPM将基于整个服务器监视空闲线程数。如果服务器中总的空闲线程数太多,子进程将杀死多余的空闲线程。MaxSpareThreads的取值范围是有限制的。Apache将按照如下限制自动修正你设置的值:worker要求其大于等于
MinSpareThreads加上ThreadsPerChild的和。
ThreadsPerChild:每个子进程建立的线程数。默认值是25。子进程在启动时建立这些线程后就不再建立新的线程了。每个子进程所拥有的所有线程的总数要足够大,以便可以处理可能的请求高峰。
MaxRequestsPerChild:设置每个子进程在其生存期内允许伺服的最大请求数量。到达MaxRequestsPerChild的限制后,子进程将会结束。如果MaxRequestsPerChild为"0",子进程将永远不会结束。将MaxRequestsPerChild设置成非零值有两个好处:可以防止(偶然的)内存泄漏无限进行而耗尽内存;
给进程一个有限寿命,从而有助于当服务器负载减轻的时候减少活动进程的数量。
如果设置为非零值,笔者建议设为10000-30000之间的一个值。
公式:
ThreadLimit >= ThreadsPerChild
MaxClients <= ServerLimit *
ThreadsPerChild,并且MaxClients必须是ThreadsPerChild的倍数
MaxSpareThreads >= MinSpareThreads+ThreadsPerChild
------------------------------------------------------------------------------------------------------------------------------------------------
接下来配置上面提到的conf/workers.properties文件和conf/uriworkermap.properties文件:
进入apache服务器的conf目录
[root@lxp2 ~]# cd /usr/local/apache2/conf/
建立workers.properties和uriworkermap.properties文件
下面给出我已经配置好的两个文件
#
# workers.properties
#
# list the workers by name
worker.list=loadBalanceServers, jk_watcher
# localhost server 1
# ------------------------
worker.s1.port=8109
worker.s1.host=localhost
worker.s1.type=ajp13
worker.s1.lbfactor=10
worker.s1.cachesize=5
# localhost server 2
# ------------------------
worker.s2.port=8209
worker.s2.host=localhost
worker.s2.type=ajp13
worker.s2.lbfactor=10
worker.s2.cachesize=5
worker.loadBalanceServers.type=lb
worker.loadBalanceServers.balanced_workers=s1,s2
worker.loadBalanceServers.sticky_session=false
worker.jk_watcher.type=status
# worker.jk_watcher.read_Only=True
worker.jk_watcher.mount=/admin/jk
worker.retries=3
worker.list
首先配置了两个worker,一个用于负载均衡,一个用于监视负载均衡状态。别名分别为loadBalanceServers和jk_watcher
然后分别配置位于本机的两个负载均衡服务器
worker.s1.port:第一台负载均衡服务器AJP协议连接器的连接端口,这里配置为8109
worker.s1.host:第一台负载均衡服务器的主机名、域名或者IP地址,这里配置为本机localhost
worker.s1.type:JK模块实现负载均衡采用的是AJP协议1.3版本,因此第一台负载均衡服务器的类型配置为ajp13
worker.s1.lbfactor:第一台负载均衡服务器在整个负载均衡系统中所占的权重,这里配置为10,权重越大,越有可能处理更多的请求,建议给性能好的机器配置更高的权重。
worker.s1.cachesize:apache服务器是多线程的,tomcat能够利用这一优势来维持一定数量的连接作为缓存。根据用户的多少来配置一个合适缓存连接数量有助于提高性能。这里配置为5
2013年7月8日补充:最近配置的这台单击集群出现了问题,在高并发量的情况下经常会报HTTP
503错误,这里我在每个worker上配置了如下参数:
worker.s1.connection_pool_size=800
worker.s1.connection_pool_minsize=25
worker.s1.connection_pool_timeout=600
同样的配置也为s2增加了一份。这样JK组件和tomcat之间的连接池数量就增加了。另外为了应付大并发量下linux文件句柄不够用的情况,还需要配置ulimit
-n
我这里配置的是65535。
s1是第一台负载均衡服务器的别名,这个别名要牢记,因为在接下来的配置中还会用到。
s2作为第二台负载均衡服务器,配置与s1大致相同。区别是AJP协议连接器的连接端口与s1的不同,这是因为要在同一台物理机上部署两个tomcat服务器的缘故。如果是两台物理机,则可以配置相同的端口,那么host属性就应该不一样了。两个tomcat服务器的权重都是10,则两个tomcat服务器将会有相同的处理请求的机会。
worker.loadBalanceServers.type:设置名称为“loadBalanceServers”的worker类型,这里配置为lb,也就是Load
Balance负载均衡
worker.loadBalanceServers.balanced_workers:设置名称为“loadBalanceServers”的worker拥有哪些负责负载均衡的服务器实例,这里配置为s1和s2