最近在开发的项目需要承受很高的并发量。综合各种情况,决定使用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
[[email protected] ~]# cat /etc/redhat-releaseCentOS release 5.7 (Final)
[[email protected] ~]# 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
[[email protected] ~]# 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.
[[email protected] ~]# 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.
[[email protected] ~]# 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)
[[email protected] ~]#
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服务器源码目录并执行配置脚本:
[[email protected] Downloads]# cd httpd-2.2.21[[email protected] 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
[[email protected] Downloads]# tar -xf apr-1.4.5.tar.gz[[email protected] Downloads]# tar -xf apr-util-1.3.12.tar.gz
进入apr,并编译
[[email protected] Downloads]# cd apr-1.4.5[[email protected] 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
[[email protected] apr-1.4.5]# ./configure
生成了MakeFile后直接编译
[[email protected] apr-1.4.5]# lsapr-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
[[email protected] apr-1.4.5]# make
编译好之后使用root权限安装:
[[email protected] apr-1.4.5]# sudo make install
然后使用类似的方法配置apr-util:
[[email protected] Downloads]# cd apr-util-1.3.12[[email protected] apr-util-1.3.12]# ./configure --with-apr=/usr/local/apr
编译apr-util:
[[email protected] apr-util-1.3.12]# make
编译好之后使用root权限安装:
[[email protected] apr-util-1.3.12]# sudo make install
当然如果你在配置apache服务器编译的时候没有提示缺少“APR”,请忽略上面关于APR编译的几步。
回到apache服务器源码所在目录,开始编译:
[[email protected] httpd-2.2.21]# make
编译过程大概不到十分钟,完成之后使用root权限进行安装
[[email protected] httpd-2.2.21]# sudo make install
如果不出意外,至此apache就安装成功了。来测试一下:
进入apache服务器的bin目录,并启动服务器:
[[email protected] httpd-2.2.21]# cd /usr/local/apache2/bin/[[email protected] 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权限。然后在该目录下执行
[[email protected] init.d]# chkconfig --add httpd
将服务添加到系统。脚本的具体解释请参阅我的另外一篇博文:
Linux中将memcached注册为系统服务(地址:http://blog.csdn.net/chaijunkun/article/details/7000600)。
6.编译JK连接器
刚刚完成了apache服务器的编译,接下来顺便把JK连接器也编译出来。
进入刚刚解压出来的tomcat-connector目录,再进入native目录。执行配置:
[[email protected] Downloads]# cd tomcat-connectors-1.2.32-src[[email protected] tomcat-connectors-1.2.32-src]# ls
BUILD.txt conf docs jkstatus LICENSE native NOTICE support tools xdocs
[[email protected] tomcat-connectors-1.2.32-src]# cd native/
[[email protected] 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
[[email protected] 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命令:
[[email protected] 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的,这一点请注意。如下所示:
[[email protected] native]# lsaclocal.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
[[email protected] native]# cd apache-2.0/
[[email protected] 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
[[email protected] apache-2.0]#
我们现在将编译好的mod_jk.so拷贝到apache服务器的modules目录中,这个目录是专门用来存放扩展模块的:
[[email protected] apache-2.0]# sudo cp ./mod_jk.so /usr/local/apache2/modules/[[email protected] apache-2.0]# cd /usr/local/apache2/modules/
[[email protected] 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:
[[email protected] ~]# cd Downloads/[[email protected] 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
[[email protected] Downloads]# mv apache-tomcat-6.0.33 tomcat_server_1
[[email protected] Downloads]# cp -r tomcat_server_1 tomcat_server_2
[[email protected] 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
[[email protected] 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:
[[email protected] bin]# ./startup.shUsing 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关闭
[[email protected] bin]# ./shutdown.shUsing 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
然后在写有<IfModule XXXX>的区域追加一行如下配置
<IfModule jk_module>
JkWorkersFile conf/workers.properties
JkMountFile conf/uriworkermap.properties
JkLogFile logs/mod_jk.log
JkLogLevel warn
</IfModule>
下面给出了一个我写的配置。注意配置中有注释的地方。“#”开头的行为注释行。已经去除了原有的配置中的多余注释。
ServerRoot "/usr/local/apache2"Listen 80
ServerName 0.0.0.0
ServerAdmin [email protected]
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
<IfModule !mpm_netware_module>
<IfModule !mpm_winnt_module>
User daemon
Group daemon
</IfModule>
</IfModule>
<IfModule dir_module>
DirectoryIndex index.html
</IfModule>
# Load Configure while Loading JK Connector Module
<IfModule jk_module>
JkWorkersFile conf/workers.properties
JkMountFile conf/uriworkermap.properties
JkLogFile logs/mod_jk.log
JkLogLevel warn
</IfModule>
# Apache Server is working in worker mode
<IfModule worker.c>
StartServers 5
ServerLimit 20
ThreadLimit 200
MaxClients 4000
MinSpareThreads 25
MaxSpareThreads 250
ThreadsPerChild 200
MaxRequestsPerChild 1000
</IfModule>
<FilesMatch "^.ht">
Order allow,deny
Deny from all
Satisfy All
</FilesMatch>
ErrorLog "logs/error_log"
LogLevel warn
<IfModule log_config_module>
LogFormat "%h %l %u %t "%r" %>s %b "%{Referer}i" "%{User-Agent}i"" combined
LogFormat "%h %l %u %t "%r" %>s %b" common
<IfModule logio_module>
LogFormat "%h %l %u %t "%r" %>s %b "%{Referer}i" "%{User-Agent}i" %I %O" combinedio
</IfModule>
CustomLog "logs/access_log" common
</IfModule>
<IfModule alias_module>
ScriptAlias /cgi-bin/ "/usr/local/apache2/cgi-bin/"
</IfModule>
<IfModule cgid_module>
</IfModule>
DefaultType text/plain
<IfModule mime_module>
TypesConfig "conf/mime.types"
AddType application/x-compress .Z
AddType application/x-gzip .gz .tgz
</IfModule>
<IfModule ssl_module>
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
</IfModule>
<Directory "/">
Options FollowSymLinks
Deny from all
Order deny,allow
AllowOverride None
</Directory>
<Directory "/usr/local/apache2/htdocs">
Options FollowSymLinks Indexes
Allow from all
Order allow,deny
AllowOverride None
</Directory>
<Directory "/usr/local/apache2/cgi-bin">
Options None
Allow from all
Order allow,deny
AllowOverride None
</Directory>
LoadModule表示当apache服务启动时要加载模块 jk_module为模块的别名,后面跟的modules/mod_jk.so就是相对于apache服务器所在目录(/usr/local/apache2/)的模块文件名。
<IfModule jk_module>区域表示当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
------------------------------------------------------------------------------------------------------------------------------------------------
<IfModule worker.c>区域表示当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目录
[[email protected] ~]# 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=800worker.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