一、Tomcat的连接器
Tomcat的连接器分为两类:HTTP连接器和Web连接器
Tomcat的HTTP连接器有三种:
1.基于java的HTTP/1.1连接器,这也是Tomcat默认使用的连接器,即Coyote,它是Tomcat作物standalone模式工作时所用到的连接器,可直接响应来自用户浏览器的关于JSP、servlet和HTML的请求,定义在server.xml当中,默认使用8080端口
2.Java开发的高性能NIO HTTP/1.1连接器,他支持非阻塞IO和Comnet,在基于库想tomcat发起请求时,此连接器表现不俗,但其实先不成熟,有严重bug存在
3.C/C++开发的native APR HTTP/1.1连接器:在负载较大场景中,此连接器可以提供非常好的性能,APR及Apache Portable Runtime,它是一个能够让开发者采用与平台无关的风格的方式来开发C/C++代码本地库,它能够很好的跨Windows,Linux和类Unix平台工作,此连接器从三个主要方面优化了系统性能并提升了系统的伸缩能力:(1)使用sendfike()内核模式调用发送大的静态文件;(2)仅使用一个native code保持大量的连接;(3)使用能够加速SSL请求处理的OpenSSL本地代码
启用APR连接器的条件:
1.将连接器的protocol属性设定为org.apache.coyote.http11.Http11AprProtocol
2.APR的库文件已经在系统库五年级的搜索路径内
基于连接器提供Tomcat性能的方法
1.设置tcpNoDelay属性值为“true”
2.通过maxKeepAliveRequest属性调整允许keep-alive功能的请求的最大数目,值为1时表示禁用
3.调整socketBuffer属性的值可以改变套接字缓冲的大小
4.将enableLookups设置为false以禁用DNS反解
5.Tomcat是一个多线程的Servlet容器,使用线程池能对服务器性能带去很大的影响,这主要通过maxThreads、maxSpareThreads和minSpareThreads来定义
6.通过JAVA_OPTS.如-Xms和-Xmx设定JVM相关的参数以定义其使用内存的能力
AJP(Apache JServ Protocol)是面向数据包的基于TCP/IP的协议,它在Apache和Tomcat的实例之间提供一个专用的通信新信道。目前常用的AJP协议的版本是1.3,它主要有以下特征
1.在快速网络有着较好的特性表现,支持数据压缩传输
2.支持SSL,加密及客户端证书
3.支持Tomcat实例集群
4.支持在apache和tomcat之间的连接的重用
Apache可以通过mod_jk和mod_proxy模块跟Tomcat整合,但mod_proxy只有在apache2.2系列的版本才直接提供,但它可以提供更丰富的功能和安全性,而对于apache1.3和2.0系类mod_jk才更适用
会话管理:分为标准会话管理器和持久会话管理器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
标准会话管理器(StandardManager) <Manager className= "org.apache.catclina.session.StandardManager" maxInactiveInterval= "7200" />
默认保存于$CATALINA_HOME/work/Catalina/<hostname>/<webapp-name>/下的SESSIONS.ser文件中 maxActiveSessions:最多允许的活动会话数量,默认为- 1 ,表示不限制
maxINactiveInterval:非活动的会话超时时长,默认为60s pathname:会话文件的保存目录 持久会话管理器(PersistentManager) 将会话数据保持至持久存储中,并且能在服务器意外中止后重新启动时重新加载这些会话信息,持久会话管理器支持将会话保存在文件存储(FileStore)和JDBC存储(JDBCStore)中 保存至文件中的示例 <Manager className= "org.apache.catalina.session.PersistentManager" saveOnRestart= "true" >
<Store className= "org.apache.catalina.session.FileStore" directory= "/data/tomcat-sessions" />
</Manager> 每个用户的会话会被保持至director指定的目录中的文件中,文件名为<session id>.session,通过后台线程每个一段时间(checkInterval参数定义,默认为 60 秒)检查一次超时会话
保存至JDBCStore中的示例 <Manager className= "org.apache.catalina.session.PersistentManager" saveOnRestart= "true" >
<Store className= "org.apache.catalina.session.JDBCStore" driveName= "com.mysql.jdbc.Driver" connectionURL= "jdbc.mysql://localhost:3306/mydb?user=user;password=passwd" />
</Manager> |
二、基于Apahce的mod_proxy与tomcat连接
1.环境规划
Apache 192.168.1.201
Tomcat 192.168.1.202 192.168.1.203
2.编译安装Apache,本处将不再累赘关于apr和apr-util的安装,关于两者的安装请移步至本人相关博客http://wangfeng7399.blog.51cto.com/3518031/1379373
1
2
3
|
[root@node1 ~]# tar xf httpd- 2.4 . 9 .tar.bz2
[root@node1 ~]# cd httpd- 2.4 . 9
[root@node1 httpd- 2.4 . 9 ]# ./configure --prefix=/usr/local/apache --sysconfdir=/etc/httpd --enable-so --enable-ssl --enable-cgi --enable-rewrite -- with -zlib -- with -pcre -- with -apr=/usr/local/apr -- with -apr-util=/usr/local/apr-util --enable-mpms-shared=all -- with -mpm=event --enable-proxy --enable-proxy-http --enable-proxy-ajp --enable-proxy-balancer --enable-lbmethod-heartbeat --enable-heartbeat --enable-slotmem-shm --enable-slotmem-plain --enable-watchdog
|
为程序提供启动脚本,并使其能够自动启动,具体内容其参照上面连接
如果启动不了的话,将LoadModule slotmem_shm_module modules/mod_slotmem_shm.so的注释取消即可
3.配置apache通过mod_proxy模块与Tomcat连接
要使用mod_proxy与Tomcat实例连接,需要apache已经装载mod_proxy、mod_proxy_http、mod_proxy_ajp和proxy_banlancer_module(实现Tomcat集群时使用)等模块
1
2
3
4
5
6
7
|
[root@node1 ~]# httpd -D DUMP_MODULES |grep proxy proxy_module (shared)
proxy_balancer_module (shared)
proxy_ftp_module (shared)
proxy_http_module (shared)
proxy_ajp_module (shared)
proxy_connect_module (shared)
|
在apache的全局配置端或虚拟主机中添加如下内容,也可以使用单独的配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
ProxyVia Off ProxyRequests Off ProxyPreserveHost Off ProxyPass / ajp: //192.168.1.202:8009/
ProxyPassReverse / ajp: //192.168.1.202:8009/
<Location / > Require all granted
</Location> 或者让apache跟Tomcat的HTTP连接器进行结合 ProxyVia Off ProxyRequests Off ProxyPreserveHost Off ProxyPass / http: //192.168.1.202:8080/
ProxyPassReverse / http: //192.168.1.202:8080/
<Location / > Require all granted
</Location> |
关于上述apache指令的说明
ProxyPreserveHost {On|Off}:如果启用此功能,代理会将用户请求的报文中的Host:行发送给后端服务器,而不再使用ProxyPass指定的服务器地址。如果想在反向代理中支持虚拟主机,则需要开启此项,否则就不需要打开此功能
ProxyVia {On|Off|Full|Block}:用于控制在http首部是否使用Via:主要用于控制在多级代理中控制代理请求的流向。默认为off,即不启用此功能,On表示每个请求和响应报文均添加Via:,Full表示每个Via:行都会添加当前apache服务器的版本号信息,Block表示每个代理请求报文中的Via:都会被移除
ProxyRequests{On|Off}:是否开启apache正向代理的功能,启用此选项为了代理http协议必须启用mod_proxy_http模块。同时,如果为apache设置了ProxyPass,则必须将ProxyRequests设置为Off
ProxyPass [path] ![url [key=value key=value ....]]:将后端服务器某URL与当前服务器的某虚拟机路径关联起来作为提供服务的路径。path为当前服务器上的某虚拟路径,url为后端服务器上的某URL路径,使用此指令必须ProxyRequests设置为Off。需要注意的是,如果path以"/"结尾,则对应的url也必须以"/"结尾,反之亦然,另外,mod_proxy模块在httpd2.1的版本之后支持与后端服务器的连接池功能,连接在按需创建的连接池中以备进一步使用,连接池大小或其他设定可以在ProxyPass中使用key=value的方式定义。常用的key如下所示
min:连接池的最小容量,此值与实际连接个数无关,仅表示连接池最小有初始化的空间大小
max:连接池的最大容量,每个MPM都有自己独立的容量,都与MPM本身有关,如Prefork的总数为1,而其它的则取决于ThreadsPerChild指令的值
loadfactor:用于负载均衡集群配置中,定于对用后端服务器的权重,取值范围为1-100
retry:当apache将请求发送至后端服务器得到错误响应时等待多长时间以后再重试,单位为秒
如果Proxy指定是以balancer://开头,即用于负载均衡集群时,其还可以接受一些特殊的参数
ldmethod:apache实现负载均衡的调度方法,默认是byrequests,即基于权重将统计请求个数进行调度,bytraffic则表示基于权重的流量技术来调度,bybusyness通过考量每个后端服务器的当前负载进行调度
maxattempts:放弃请求之前实现故障转移的次数,默认为1,其最大值不应该大于总的节点数
nofailover:取值为On或Off,设置为On时表示后端服务器故障时,用户session将损坏,因此,在后端服务器不支持session复制时可以将其设置为On
stickysession:调度器的stick session的名称,根据web程序语言的不同,其值为JSESSIONID或PHPSESSIONID
可以看到我们的反向代理是成功的
4.配置mod_proxy实现负载均衡,将前面的配置文件改为如下内容,本处使用的为http协议
1
2
3
4
5
6
7
8
9
10
|
ProxyVia Off ProxyRequests Off ProxyPreserveHost Off <Proxy balancer: //wangfeng7399>
BalancerMember http: //192.168.1.202:8080/ loadfactor=10 route=TomcatA
BalancerMember http: //192.168.1.203:8080/ loadfactor=10 route=TomcatB
ProxySet lbmethod=bytraffic </Proxy> ProxyPass / balancer: //wangfeng7399/
ProxyPassReverse / balancer: //wangfeng7399/
|
在192.168.1.202上添加testjsp页面,内容如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<%@ page language= "java" %>
<html> <head><title>TomcatA</title></head>
<body>
<h1><font color= "red" >TomcatA </font></h1>
<table align= "centre" border= "1" >
<tr>
<td>Session ID</td>
<% session.setAttribute( "abc" , "abc" ); %>
<td><%= session.getId() %></td>
</tr>
<tr>
<td>Created on</td>
<td><%= session.getCreationTime() %></td>
</tr>
</table>
</body>
</html> |
在192.168.1.203上,添加test.jsp,内容如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<%@ page language= "java" %>
<html> <head><title>TomcatB</title></head>
<body>
<h1><font color= "blue" >TomcatB </font></h1>
<table align= "centre" border= "1" >
<tr>
<td>Session ID</td>
<% session.setAttribute( "abc" , "abc" ); %>
<td><%= session.getId() %></td>
</tr>
<tr>
<td>Created on</td>
<td><%= session.getCreationTime() %></td>
</tr>
</table>
</body>
</html> |
可以看到我们请求到的页面完全不同,这说明我们的负载均衡搭建成功,如果想要基于session绑定服务器应该添加stickysession=JSESSIONID
5.配置apache通过mod_jk模块与Tomcat连接
mod_jk是ASF的一个项目,是一个工作与apache端基于AJP协议与Tomcat通信的连接器,它是apache的一个模块,是AJP的客户端(服务端是Tomcat的AJP连接器)
1
2
3
4
5
|
[root@node1 ~]# wget http: //mirrors.cnnic.cn/apache/tomcat/tomcat-connectors/jk/tomcat-connectors-1.2.40-src.tar.gz
[root@node1 ~]# tar xf tomcat-connectors- 1.2 . 40 -src.tar.gz
[root@node1 ~]# cd tomcat-connectors- 1.2 . 40 -src/ native /
[root@node1 native ]# ./configure -- with -apxs=/usr/local/httpd/bin/apxs
[root@node1 native ]# make && make install
|
apache要使用mod_jk连接器,需要在启动时加载此连接模块,为了便于管理与mod_jk模块的相关配置,这里使用一个专门的配置文件/etc/httpd24/extra/mod_jk.conf来保存相关的指令
1
2
3
4
5
6
|
LoadModule jk_module modules/mod_jk.so JkWorkersFile /etc/httpd24/extra/workers.properties JkLogFile logs/mod_jk.log JkLogLevel error JkMount /* TomcatA JkMount /status/ stat1 |
除了需要使用LoadModule指令在apache中装载模块,mod_jk还需要在apache的主配置文件中设置其他一些指令来配置其工作属性。如JkWorkersFile则是用来指定保存了worker相关工作属性定义的配置文件,JklogFile则用于指定mod_jk模块的日志文件,JkLogLevel则可以用来指定日志的级别(info,error,debug),此外还可以使用JkRequestLogFormant定义日志信息的格式。而JkMount(格式:JkMount <本地URL> <Tomcat的工作目录>)来指定用于控制URL和Tomcat workers的对应关系
为了让apache能使用自定义的配置文件,需要在httpd的主配置文件中,添加如下行
1
|
Include /etc/httpd24/extra/mod_jk.conf |
对于apache代理来说,每一个后端的Tomcat实例中的engine都可以视作为一个worker,而每一个worker的地址、连接器的端口等信息都需要在apache端指定以便apache可以识别并使用这些worker。约定俗成,配置这些信息的文件通常为workers.preoperties(即上面JkWorkersFile)指定的文件,在apache启动时,mod_jk会扫描此文件获取每一个worker的配置信息。
workers.preoperties文件一般有两类指令组成,一是mod_jk可以连接的各worker名称列表,二是每一个worker的属性配置信息,它们分别遵循如下使用语法
worker.list = <a comma separated list of worker names >
worker.<worker name>.<property> = <property value>
其中worker.list指令可以重复指定多次,而worker name则是Tomcat中engine组件jvmRoute参数的值
根据某工作机制的不同,worker有多种不同的类型,这时需要为每个worker定义一项属性worker.<worker name>.type,常见的类型如下
ajp13:此类型表示当前worker为一个运行着的Tomcat实例。
lb:lb即load balancing,专用于负载均衡场景中的worker,此worker并不真正负责处理用户请求,而是将用户请求调度至其他类型为ajp13的worker
status:用户显示分布式环境中各实际情况worker工作状态的特殊worker,他不处理任何请求,也不管连任何实际工作的worker实例
worker其他常见的属性说明:
host:Tomcat的worker实例所在的主机
prot:Tomcat实例上AJP1.3连接器的端口
connection_pool_minsize:最少要保持在连接池中的连接个数:默认为pool_size/2
connection_pool_timeout:连接池中连接的超时时长
mount:由当前worker提供的context路径,如果有多个则使用空格隔开,此属性可以有Jkmount指令代替
retries:错误发生时的重试次数
socket_timeout:mod_jk等待worker响应的市场,默认为0,即无限等待
socket_keepalive:是否启用keep alive的功能,1表示启用,0表示禁用
lbfactor:worker的权重,可以在负载均衡的应用场景中卫worker定义此属性
另外,在负载均衡模式中,专用的属性还有
balance_workers:用户负载均衡模式中的各worker的名称列表,需要注意的是,出现在此处的worker名称一定不能再任何worker.list属性列表中定义过,并且worker.list属性定义的worker名称必须包含负载均衡worker
method:可以设定为R、T或B,默认为R,及根据请求的个数进行调度,T表示根据已经发送给worker的实际流量大小进行调度,B表示根据实际负载均衡情况进行调度
sticky_session:在此将某请求调度至某worker后,源于此值得所有后续请求都将直接调度至此worker,实现将用户session与某worker绑定。默认的值为1,即启用此功能,如果后端的各worker之间支持session复制,则可以将此值设定为0
根据前文中的指定,应该使用/etc/httpd24/extra/workers.properties来定义个名为TomcatA的worker,并为其指定几个属性,如下所示
1
2
3
4
5
6
|
worker.list=TomcatA,stat1 worker.TomcatA.port= 8009
worker.TomcatA.host= 192.168 . 1.202
worker.TomcatA.type=ajp13 worker.TomcatA.lbfactor= 1
worker.stat1.type = status |
将192.168.1.202上tomcat的主配置文件中的内容作如下修改
1
2
3
4
|
将如下内容 <Engine name= "Catalina" defaultHost= "localhost" >
修改为 <Engine name= "Catalina" defaultHost= "localhost" jvmRoute= "TomcatA" >
|
可以看到现在访问正常了
还可以查看后端的转状态显示页
6.配置基于mod_jk的负载均衡
为了避免用户直接访问后端Tomcat实例,影响负载均衡的效果,建议在Tomcat的各实例上禁用HTTP/1.1连接器
将/etc/httpd24/extra/mod_jk.conf中的内容修改为如下内容
1
2
3
4
5
6
|
LoadModule jk_module modules/mod_jk.so JkWorkersFile /etc/httpd24/extra/workers.properties JkLogFile logs/mod_jk.log JkLogLevel debug JkMount /* lbcluster JkMount /status/ stat1 |
将/etc/httpd24/extra/workers.properties内容修改为如下内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
worker.list=lbcluster,stat1 worker.TomcatA.port= 8009
worker.TomcatA.host= 192.168 . 1.202
worker.TomcatA.type=ajp13 worker.TomcatA.lbfactor= 1
worker.TomcatB.port= 8009
worker.TomcatB.host= 192.168 . 1.203
worker.TomcatB.type=ajp13 worker.TomcatB.lbfactor= 1
worker.lbcluster.type=lb worker.lbcluster.sticky_session= 0
worker.lbcluster.balance_workers=TomcatA,TomcatB worker.stat1.type = status ~ |
将192.168.1.202上tomcat的主配置文件中的内容作如下修改
1
2
3
4
|
将如下内容 <Engine name= "Catalina" defaultHost= "localhost" >
修改为 <Engine name= "Catalina" defaultHost= "localhost" jvmRoute= "TomcatA" >
|
将192.168.1.203上的tomcat的主配置文件中的内容做如下修改
1
2
3
4
|
将如下内容 <Engine name= "Catalina" defaultHost= "localhost" >
修改为 <Engine name= "Catalina" defaultHost= "localhost" jvmRoute= "TomcatB" >
|
可以看到我们的集群搭建完成,如果想保持会话,只需要将worker.lbcluster.sticky_session=1即可
三、基于session复制保证会话的同步
我们可以看到上面做的负载均衡不能保证会话的同步,下面我们来通过session复制的方式来保证会话的同步
修改192.168.1.202和192.168.1.203上的Tomcat的主配置文件,在<engine>中添加如下内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
<Cluster className= "org.apache.catalina.ha.tcp.SimpleTcpCluster"
channelSendOptions= "8" >
<Manager className= "org.apache.catalina.ha.session.DeltaManager"
expireSessionsOnShutdown= "false"
notifyListenersOnReplication= "true" />
<Channel className= "org.apache.catalina.tribes.group.GroupChannel" >
<Membership className= "org.apache.catalina.tribes.membership.McastService"
address= "228.0.0.4"
port= "45564"
frequency= "500"
dropTime= "3000" />
<Receiver className= "org.apache.catalina.tribes.transport.nio.NioReceiver"
address= "auto"
port= "4000"
autoBind= "100"
selectorTimeout= "5000"
maxThreads= "6" />
<Sender className= "org.apache.catalina.tribes.transport.ReplicationTransmitter" >
<Transport className= "org.apache.catalina.tribes.transport.nio.PooledParallelSender" />
</Sender>
<Interceptor className= "org.apache.catalina.tribes.group.interceptors.TcpFailureDetector" />
<Interceptor className= "org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor" />
</Channel>
<Valve className= "org.apache.catalina.ha.tcp.ReplicationValve"
filter= "" />
<Valve className= "org.apache.catalina.ha.session.JvmRouteBinderValve" />
<Deployer className= "org.apache.catalina.ha.deploy.FarmWarDeployer"
tempDir= "/tmp/war-temp/"
deployDir= "/tmp/war-deploy/"
watchDir= "/tmp/war-listen/"
watchEnabled= "false" />
<ClusterListener className= "org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener" />
<ClusterListener className= "org.apache.catalina.ha.session.ClusterSessionListener" />
</Cluster>
|
在需要做会话保持的虚拟主机上的WEB-INF的web.xml中添加<distributable/>,要不会话不会保持
终于写完了,好漫长的一次写作,希望对各位能够有所帮助,同时欢迎各位大神提意见
本文转自wangfeng7399 51CTO博客,原文链接:http://blog.51cto.com/wangfeng7399/1409341,如需转载请自行联系原作者