一、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
<code>标准会话管理器(StandardManager)</code>
<code><Manager className=</code><code>"org.apache.catclina.session.StandardManager"</code> <code>maxInactiveInterval=</code><code>"7200"</code> <code>/></code>
<code>默认保存于$CATALINA_HOME/work/Catalina/<hostname>/<webapp-name>/下的SESSIONS.ser文件中</code>
<code>maxActiveSessions:最多允许的活动会话数量,默认为-</code><code>1</code><code>,表示不限制</code>
<code>maxINactiveInterval:非活动的会话超时时长,默认为60s</code>
<code>pathname:会话文件的保存目录</code>
<code>持久会话管理器(PersistentManager)</code>
<code>将会话数据保持至持久存储中,并且能在服务器意外中止后重新启动时重新加载这些会话信息,持久会话管理器支持将会话保存在文件存储(FileStore)和JDBC存储(JDBCStore)中</code>
<code>保存至文件中的示例</code>
<code><Manager className=</code><code>"org.apache.catalina.session.PersistentManager"</code> <code>saveOnRestart=</code><code>"true"</code><code>></code>
<code> </code><code><Store className=</code><code>"org.apache.catalina.session.FileStore"</code> <code>directory=</code><code>"/data/tomcat-sessions"</code> <code>/></code>
<code></Manager></code>
<code>每个用户的会话会被保持至director指定的目录中的文件中,文件名为<session id>.session,通过后台线程每个一段时间(checkInterval参数定义,默认为</code><code>60</code><code>秒)检查一次超时会话</code>
<code>保存至JDBCStore中的示例</code>
<code> </code><code><Store className=</code><code>"org.apache.catalina.session.JDBCStore"</code> <code>driveName=</code><code>"com.mysql.jdbc.Driver"</code> <code>connectionURL=</code><code>"jdbc.mysql://localhost:3306/mydb?user=user;password=passwd"</code><code>/></code>
二、基于Apahce的mod_proxy与tomcat连接
1.环境规划
Apache 192.168.1.201
Tomcat 192.168.1.202 192.168.1.203
<code>[root@node1 ~]# tar xf httpd-</code><code>2.4</code><code>.</code><code>9</code><code>.tar.bz2</code>
<code>[root@node1 ~]# cd httpd-</code><code>2.4</code><code>.</code><code>9</code>
<code>[root@node1 httpd-</code><code>2.4</code><code>.</code><code>9</code><code>]# ./configure --prefix=/usr/local/apache --sysconfdir=/etc/httpd --enable-so --enable-ssl --enable-cgi --enable-rewrite --</code><code>with</code><code>-zlib --</code><code>with</code><code>-pcre --</code><code>with</code><code>-apr=/usr/local/apr --</code><code>with</code><code>-apr-util=/usr/local/apr-util --enable-mpms-shared=all --</code><code>with</code><code>-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</code>
为程序提供启动脚本,并使其能够自动启动,具体内容其参照上面连接
如果启动不了的话,将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集群时使用)等模块
<code>[root@node1 ~]# httpd -D DUMP_MODULES |grep proxy</code>
<code> </code><code>proxy_module (shared)</code>
<code> </code><code>proxy_balancer_module (shared)</code>
<code> </code><code>proxy_ftp_module (shared)</code>
<code> </code><code>proxy_http_module (shared)</code>
<code> </code><code>proxy_ajp_module (shared)</code>
<code> </code><code>proxy_connect_module (shared)</code>
在apache的全局配置端或虚拟主机中添加如下内容,也可以使用单独的配置文件
<code>ProxyVia Off</code>
<code>ProxyRequests Off</code>
<code>ProxyPreserveHost Off</code>
<code> </code><code>ProxyPass / ajp:</code><code>//192.168.1.202:8009/</code>
<code> </code><code>ProxyPassReverse / ajp:</code><code>//192.168.1.202:8009/</code>
<code><Location / ></code>
<code> </code><code>Require all granted</code>
<code></Location></code>
<code>或者让apache跟Tomcat的HTTP连接器进行结合</code>
<code> </code><code>ProxyPass / http:</code><code>//192.168.1.202:8080/</code>
<code> </code><code>ProxyPassReverse / http:</code><code>//192.168.1.202:8080/</code>
关于上述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
可以看到我们的反向代理是成功的
4.配置mod_proxy实现负载均衡,将前面的配置文件改为如下内容,本处使用的为http协议
<code><Proxy balancer:</code><code>//wangfeng7399></code>
<code>BalancerMember http:</code><code>//192.168.1.202:8080/ loadfactor=10 route=TomcatA</code>
<code>BalancerMember http:</code><code>//192.168.1.203:8080/ loadfactor=10 route=TomcatB</code>
<code>ProxySet lbmethod=bytraffic</code>
<code></Proxy></code>
<code>ProxyPass / balancer:</code><code>//wangfeng7399/</code>
<code>ProxyPassReverse / balancer:</code><code>//wangfeng7399/</code>
在192.168.1.202上添加testjsp页面,内容如下
18
<code><%@ page language=</code><code>"java"</code> <code>%></code>
<code><html></code>
<code> </code><code><head><title>TomcatA</title></head></code>
<code> </code><code><body></code>
<code> </code><code><h1><font color=</code><code>"red"</code><code>>TomcatA </font></h1></code>
<code> </code><code><table align=</code><code>"centre"</code> <code>border=</code><code>"1"</code><code>></code>
<code> </code><code><tr></code>
<code> </code><code><td>Session ID</td></code>
<code> </code><code><% session.setAttribute(</code><code>"abc"</code><code>,</code><code>"abc"</code><code>); %></code>
<code> </code><code><td><%= session.getId() %></td></code>
<code> </code><code></tr></code>
<code> </code><code><td>Created on</td></code>
<code> </code><code><td><%= session.getCreationTime() %></td></code>
<code> </code><code></tr></code>
<code> </code><code></table></code>
<code> </code><code></body></code>
<code></html></code>
在192.168.1.203上,添加test.jsp,内容如下
<code> </code><code><head><title>TomcatB</title></head></code>
<code> </code><code><h1><font color=</code><code>"blue"</code><code>>TomcatB </font></h1></code>
<a href="http://s3.51cto.com/wyfs02/M01/26/EB/wKiom1NuR1SjAkXBAACwOX5qtqo881.jpg" target="_blank"></a>
<a href="http://s3.51cto.com/wyfs02/M00/26/EB/wKioL1NuRynBkCpEAADHBjqCSts293.jpg" target="_blank"></a>
可以看到我们请求到的页面完全不同,这说明我们的负载均衡搭建成功,如果想要基于session绑定服务器应该添加stickysession=JSESSIONID
5.配置apache通过mod_jk模块与Tomcat连接
mod_jk是ASF的一个项目,是一个工作与apache端基于AJP协议与Tomcat通信的连接器,它是apache的一个模块,是AJP的客户端(服务端是Tomcat的AJP连接器)
<code>[root@node1 ~]# wget http:</code><code>//mirrors.cnnic.cn/apache/tomcat/tomcat-connectors/jk/tomcat-connectors-1.2.40-src.tar.gz</code>
<code>[root@node1 ~]# tar xf tomcat-connectors-</code><code>1.2</code><code>.</code><code>40</code><code>-src.tar.gz</code>
<code>[root@node1 ~]# cd tomcat-connectors-</code><code>1.2</code><code>.</code><code>40</code><code>-src/</code><code>native</code><code>/</code>
<code>[root@node1 </code><code>native</code><code>]# ./configure --</code><code>with</code><code>-apxs=/usr/local/httpd/bin/apxs</code>
<code>[root@node1 </code><code>native</code><code>]# make && make install</code>
apache要使用mod_jk连接器,需要在启动时加载此连接模块,为了便于管理与mod_jk模块的相关配置,这里使用一个专门的配置文件/etc/httpd24/extra/mod_jk.conf来保存相关的指令
<code>LoadModule jk_module modules/mod_jk.so</code>
<code>JkWorkersFile /etc/httpd24/extra/workers.properties</code>
<code>JkLogFile logs/mod_jk.log</code>
<code>JkLogLevel error</code>
<code>JkMount /* TomcatA</code>
<code>JkMount /status/ stat1</code>
除了需要使用LoadModule指令在apache中装载模块,mod_jk还需要在apache的主配置文件中设置其他一些指令来配置其工作属性。如JkWorkersFile则是用来指定保存了worker相关工作属性定义的配置文件,JklogFile则用于指定mod_jk模块的日志文件,JkLogLevel则可以用来指定日志的级别(info,error,debug),此外还可以使用JkRequestLogFormant定义日志信息的格式。而JkMount(格式:JkMount <本地URL> <Tomcat的工作目录>)来指定用于控制URL和Tomcat workers的对应关系
为了让apache能使用自定义的配置文件,需要在httpd的主配置文件中,添加如下行
<code>Include /etc/httpd24/extra/mod_jk.conf</code>
对于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,并为其指定几个属性,如下所示
<code>worker.list=TomcatA,stat1</code>
<code>worker.TomcatA.port=</code><code>8009</code>
<code>worker.TomcatA.host=</code><code>192.168</code><code>.</code><code>1.202</code>
<code>worker.TomcatA.type=ajp13</code>
<code>worker.TomcatA.lbfactor=</code><code>1</code>
<code>worker.stat1.type = status</code>
将192.168.1.202上tomcat的主配置文件中的内容作如下修改
<a href="http://s3.51cto.com/wyfs02/M00/26/EB/wKioL1Nuau6DsbBJAAV-lB3al7I890.jpg" target="_blank"></a>
<code>将如下内容</code>
<code><Engine name=</code><code>"Catalina"</code> <code>defaultHost=</code><code>"localhost"</code><code>></code>
<code>修改为</code>
<code><Engine name=</code><code>"Catalina"</code> <code>defaultHost=</code><code>"localhost"</code> <code>jvmRoute=</code><code>"TomcatA"</code><code>></code>
可以看到现在访问正常了
还可以查看后端的转状态显示页
<a href="http://s3.51cto.com/wyfs02/M02/26/EB/wKioL1NucyGizOqTAARVYNIk6Zs756.jpg" target="_blank"></a>
6.配置基于mod_jk的负载均衡
为了避免用户直接访问后端Tomcat实例,影响负载均衡的效果,建议在Tomcat的各实例上禁用HTTP/1.1连接器
将/etc/httpd24/extra/mod_jk.conf中的内容修改为如下内容
<code>JkLogLevel debug</code>
<code>JkMount /* lbcluster</code>
将/etc/httpd24/extra/workers.properties内容修改为如下内容
<code>worker.list=lbcluster,stat1</code>
<code>worker.TomcatB.port=</code><code>8009</code>
<code>worker.TomcatB.host=</code><code>192.168</code><code>.</code><code>1.203</code>
<code>worker.TomcatB.type=ajp13</code>
<code>worker.TomcatB.lbfactor=</code><code>1</code>
<code>worker.lbcluster.type=lb</code>
<code>worker.lbcluster.sticky_session=</code><code>0</code>
<code>worker.lbcluster.balance_workers=TomcatA,TomcatB</code>
<code>~</code>
将192.168.1.203上的tomcat的主配置文件中的内容做如下修改
<code><Engine name=</code><code>"Catalina"</code> <code>defaultHost=</code><code>"localhost"</code> <code>jvmRoute=</code><code>"TomcatB"</code><code>></code>
<a href="http://s3.51cto.com/wyfs02/M02/26/EB/wKioL1NudMrBuS_TAADFRcCUWh8594.jpg" target="_blank"></a>
<a href="http://s3.51cto.com/wyfs02/M01/26/EB/wKiom1NudPXRMr_vAADO9ejDQBo215.jpg" target="_blank"></a>
可以看到我们的集群搭建完成,如果想保持会话,只需要将worker.lbcluster.sticky_session=1即可
三、基于session复制保证会话的同步
我们可以看到上面做的负载均衡不能保证会话的同步,下面我们来通过session复制的方式来保证会话的同步
修改192.168.1.202和192.168.1.203上的Tomcat的主配置文件,在<engine>中添加如下内容
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<code><Cluster className=</code><code>"org.apache.catalina.ha.tcp.SimpleTcpCluster"</code>
<code> </code><code>channelSendOptions=</code><code>"8"</code><code>></code>
<code> </code><code><Manager className=</code><code>"org.apache.catalina.ha.session.DeltaManager"</code>
<code> </code><code>expireSessionsOnShutdown=</code><code>"false"</code>
<code> </code><code>notifyListenersOnReplication=</code><code>"true"</code><code>/></code>
<code> </code><code><Channel className=</code><code>"org.apache.catalina.tribes.group.GroupChannel"</code><code>></code>
<code> </code><code><Membership className=</code><code>"org.apache.catalina.tribes.membership.McastService"</code>
<code> </code><code>address=</code><code>"228.0.0.4"</code>
<code> </code><code>port=</code><code>"45564"</code>
<code> </code><code>frequency=</code><code>"500"</code>
<code> </code><code>dropTime=</code><code>"3000"</code><code>/></code>
<code> </code><code><Receiver className=</code><code>"org.apache.catalina.tribes.transport.nio.NioReceiver"</code>
<code> </code><code>address=</code><code>"auto"</code>
<code> </code><code>port=</code><code>"4000"</code>
<code> </code><code>autoBind=</code><code>"100"</code>
<code> </code><code>selectorTimeout=</code><code>"5000"</code>
<code> </code><code>maxThreads=</code><code>"6"</code><code>/></code>
<code> </code><code><Sender className=</code><code>"org.apache.catalina.tribes.transport.ReplicationTransmitter"</code><code>></code>
<code> </code><code><Transport className=</code><code>"org.apache.catalina.tribes.transport.nio.PooledParallelSender"</code><code>/></code>
<code> </code><code></Sender></code>
<code> </code><code><Interceptor className=</code><code>"org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"</code><code>/></code>
<code> </code><code><Interceptor className=</code><code>"org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"</code><code>/></code>
<code> </code><code></Channel></code>
<code> </code><code><Valve className=</code><code>"org.apache.catalina.ha.tcp.ReplicationValve"</code>
<code> </code><code>filter=</code><code>""</code><code>/></code>
<code> </code><code><Valve className=</code><code>"org.apache.catalina.ha.session.JvmRouteBinderValve"</code><code>/></code>
<code> </code><code><Deployer className=</code><code>"org.apache.catalina.ha.deploy.FarmWarDeployer"</code>
<code> </code><code>tempDir=</code><code>"/tmp/war-temp/"</code>
<code> </code><code>deployDir=</code><code>"/tmp/war-deploy/"</code>
<code> </code><code>watchDir=</code><code>"/tmp/war-listen/"</code>
<code> </code><code>watchEnabled=</code><code>"false"</code><code>/></code>
<code> </code><code><ClusterListener className=</code><code>"org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"</code><code>/></code>
<code> </code><code><ClusterListener className=</code><code>"org.apache.catalina.ha.session.ClusterSessionListener"</code><code>/></code>
<code> </code><code></Cluster></code>
在需要做会话保持的虚拟主机上的WEB-INF的web.xml中添加<distributable/>,要不会话不会保持
<a href="http://s3.51cto.com/wyfs02/M01/26/EB/wKioL1NuicrSYLalAADpe8T5oL8800.jpg" target="_blank"></a>
<a href="http://s3.51cto.com/wyfs02/M00/26/EB/wKiom1NuifWSrwFvAAEINsSLPT0125.jpg" target="_blank"></a>
终于写完了,好漫长的一次写作,希望对各位能够有所帮助,同时欢迎各位大神提意见
本文转自wangfeng7399 51CTO博客,原文链接:http://blog.51cto.com/wangfeng7399/1409341,如需转载请自行联系原作者