编译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也使用了多进程,每个进程又生成多个线程,以获得基于进程服务器的稳定性。
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连接器模块就部署完成了,但是还需要配置,具体配置将在下文中详细描述。
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
LoadModule表示当apache服务启动时要加载模块
jk_module为模块的别名,后面跟的modules/mod_jk.so就是相对于apache服务器所在目录(/usr/local/apache2/)的模块文件名。
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
------------------------------------------------------------------------------------------------------------------------------------------------
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目录
[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
worker.loadBalanceServers.sticky_session:设置负载均衡是否采用粘性会话。如果该属性设置为true,假设一个请求被s1处理了,下次来源于同一个客户端的请求也将被s1处理。直到s1已经达到最大连接数,JK才会将会话切换到其他服务器上。但是如果恰巧一直负责处理该会话的服务器down掉了,则会话将会丢失,明显的故障现象就是关于session的操作会出现莫名其妙的错误(例如你所运行的应用中用户可能已经登录了,但突然在一次访问后莫名其妙地提示没有登录)。这里配置为false,不启用粘性会话,让服务器都有机会处理请求,提高了系统的稳定性。
worker.jk_watcher.type:设置名称为“jk_watcher”的worker类型,这里配置为status,用于监视各个负载均衡服务器实例的运行状态
#
worker.jk_watcher.read_only:设置名称为“jk_watcher”的worker是否为只读。上面已经将这个worker设置为了监控worker,如果设置为只读,就不能对负载均衡服务器参数进行配置了,这里先将这条配置注释掉,默认值为false,表示可以配置参数。
worker.jk_watcher.mount:设置名称为“jk_watcher”的worker(负载均衡服务器实例监视器)的挂载路径,这里配置为/admin/jk。这样就可以通过http://127.0.0.1/admin/jk来访问监视工具了,可以很方便地看到各个负载均衡服务器的工作情况。
worker.retries:这是worker全局的重试次数。在apache服务器启动后,会最多尝试若干次去连接这些负载均衡服务器,若连接不上就认为是down掉了,这里配置为3
下面给出配置,其作用是告诉apache服务器哪些请求由负载均衡服务器处理:
#
# uriworkermap.properties
#
#define all requests will be submitted to load balance servers
#if the condition is satisfied, the filter will validate the next statement until it's not.
#notice the order of the following statements
/*=loadBalanceServers
/jkstatus=jk_watcher
!/*.gif=loadBalanceServers
!/*.jpg=loadBalanceServers
!/*.tif=loadBalanceServers
!/*.png=loadBalanceServers
在配置文件中,以“!”开头的条件表示“不要”,“=”表示交给。
因此条件“/*=loadBalanceServers”表示将任何请求交给负载均衡服务器。
条件“!/*.jpg=loadBalanceServers”表示不要将.jpg结尾的请求交给负载均衡服务器
apache服务器接收到一个请求后会按照配置文件中的约束条件一个一个地检查,然后按照最后满足的匹配条件来决定由哪个worker来处理请求。
我的测试用例中需要输入http://127.0.0.1/TestProject/showInfo.do来查看信息。那么接下来就将这个请求作为示例来解释上面配置文件的工作过程:
经过上面的条件筛选,最符合条件的就是“/*=loadBalanceServers”。因此将请求转给了负载均衡服务器。
试想一下,如果在apache主目录下放置了一个名为a.jpg的图片,访问路径为http://127.0.0.1/a.jpg,请求经过该配置的检查,最后满足的条件就是“!/*.jpg=loadBalanceServers”,不要将.jpg结尾的请求交给负载均衡服务器,因此apache服务自己处理了该请求。
.jpg是静态数据,apache由C语言实现,直接针对系统底层进行IO操作,因此静态性能优良。而tomcat作为Servlet容器,擅长的是J2EE相关业务的解析。因此通过这样配置可以实现应用的“动静态分离”,相互取长补短,优化了性能。类似地也可以将.js、.css和.html等等静态文件按照上述格式填写到uriworkermap.properties配置文件中。
10.tomcat服务器的配置
由于在同一台物理机中部署了两个tomcat服务器实例,因此需要对端口相关的设置特别小心。tomcat服务器的主配置文件server.xml位于conf目录内。为了配置简单,我将最原始server.xml配置文件中的所有注释删除,然后配置好了一个模板,该模板是s1((即tomcat_server_1)的配置文件,如下所示:
SSLEngine="on"/>
type="org.apache.catalina.UserDatabase"description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml"/>
connectionTimeout="20000"redirectPort="8443"/>
resourceName="UserDatabase"/>
autoDeploy="true"xmlValidation="false"xmlNamespaceAware="false">
channelSendOptions="8">
expireSessionsOnShutdown="false"notifyListenersOnReplication="true"/>
address="228.0.0.4"port="45564"frequency="500"dropTime="3000"/>
address="auto"port="4001"autoBind="100"selectorTimeout="5000"
maxThreads="6"/>
className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
filter=""/>
tempDir="/tmp/war-temp/"deployDir="/tmp/war-deploy/"watchDir="/tmp/war-listen/"
watchEnabled="false"/>
className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
className="org.apache.catalina.ha.session.ClusterSessionListener"/>
配置好s1服务器后再配置s2服务器。按照上面模板中的注释要求,修改相应的端口就可以了。PS:
...>
节点之间部分不必自己动手敲进去,在tomcat服务器目录的/webapps/docs/cluster-howto.html文件中有这一段文字,拷贝出来贴到server.xml文件中即可。