/ 中存储网

Linux系统中使用Apache+Tomcat+JK配置负载均衡和群集的详细过程

2014-02-11 13:54:01 来源:itjs.cn

最近在开发的项目需要承受很高的并发量。综合各种情况,决定使用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-release

CentOS 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。

下载稳定版本的Apache服务器

然后选择Unix版源码:

Unix版本Apache服务器源码

2.下载tomcat服务器源码包

目前tomcat服务器个人还是觉得6.0比较稳定。7.0毕竟是新出的东西,需要一定的生产实践考验才能达到理想的状态。因此这里选择tomcat 6.0。

访问网址http://tomcat.apache.org/download-60.cgi,可以看到目前稳定的版本为6.0.33:

Tomcat服务器

这里强烈建议下载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连接器版本:

Tomcat JK 连接器

这里还是推荐下载tar.gz格式的源码。原因同上。

4.解压

apache服务器、tomcat服务器和JK连接器都已经下载好了,如下图所示:

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

解压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]# 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

[[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!”则表示启动成功了

Apache启动成功

这里要注意一点就是Linux的防火墙问题。如果你的Linux服务器启动了防火墙,本地访问上面的网址是没有问题的,但如果其它计算机访问你的服务器有可能会连接失败。

出现这种情况的原因是防火墙将入站80端口封锁了。解决方法是将80端口加入到允许列表中:

防火墙

进入防火墙设置后,如果发现Firewall状态为Enabled,表示防火墙已启用,需要将WWW(HTTP)服务标记为信任,如果需要使用hhtps协议,还要将Secure WWW(HTTPS)服务也标记为信任。如下图所示:

允许HTTP和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]# 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

[[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.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关闭

[[email protected] 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

然后在写有<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=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