[转][笔记] 6.Tomcat系列之Apache负载均衡请求至Tomcat及DeltaManager的使用

转自陈明乾的博客,可能有一定更新。

转原文声明:
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://freeloda.blog.51cto.com/2033581/1301888

一、前言
二、环境准备
三、负载均衡实现
四、DeltaManager实现
五、Nginx实现Tomcat负载均衡

注,操作系统 CnetOS6.8 x86_64

一、前言


本博文中的所有内容是基于上一篇写的,不清楚的博友可以先看一下上一篇博文:http://freeloda.blog.51cto.com/2033581/1301382。在上一篇博文中我们分别用mod_proxy和mod_jk实现了tomcat服务器的反向代理,在这一篇博文中我们要实现tomcat服务器的负载均衡和tomcat集群的会话共享。好了,下面我们就来具体的说一下吧!

二、环境准备


1.实验拓扑

Apache: 192.168.0.171
Tomcat1: 192.168.0.181
Tomcat2: 192.168.0.182

     Apache
        |
       / \
Tomcat1  Tomcat2

2.同步各节点时间

[root@apache ~]# ntpdate 202.120.2.101
[root@tomcat1 ~]# ntpdate 202.120.2.101
[root@tomcat2 ~]# ntpdate 202.120.2.101

3.安装jdk

[root@tomcat2 src]# rpm -ivh jdk-7u40-linux-x64.rpm

4.配置jdk环境变量

[root@tomcat2 java]# vim /etc/profile.d/java.sh
export JAVA_HOME=/usr/java/jdk1.7.0_40
export PATH=$PATH:$JAVA_HOME/bin
[root@tomcat2 java]# java -version
java version "1.7.0_40" 
Java(TM) SE Runtime Environment (build 1.7.0_40-b43) 
Java HotSpot(TM) 64-Bit Server VM (build 24.0-b56, mixed mode)

5.安装tomcat

[root@tomcat2 src]# tar xf apache-tomcat-7.0.42.tar.gz -C /usr/local/
[root@tomcat2 src]# cd /usr/local/ 
[root@tomcat2 local]# ln -sv apache-tomcat-7.0.42 tomcat 
"tomcat" -> "apache-tomcat-7.0.42" 
[root@tomcat2 local]# cd tomcat/ 
[root@tomcat2 tomcat]# ls 
bin conf lib LICENSE logs NOTICE RELEASE-NOTES RUNNING.txt temp webapps work

6.配置tomcat环境变量

[root@tomcat2 tomcat]# vim /etc/profile.d/tomcat.sh
export CATALINA_HOME=/usr/local/tomcat
export PATH=$PATH:$CATALINA_HOME/bin
[root@tomcat2 tomcat]# . /etc/profile.d/tomcat.sh
[root@tomcat2 tomcat]# catalina.sh version 
Using CATALINA_BASE:  /usr/local/tomcat 
Using CATALINA_HOME:  /usr/local/tomcat 
Using CATALINA_TMPDIR: /usr/local/tomcat/temp 
Using JRE_HOME:    /usr/java/jdk1.7.0_40 
Using CLASSPATH:    /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar 
Server version: Apache Tomcat/7.0.42 
Server built:  Jul 2 2013 08:57:41 
Server number: 7.0.42.0 
OS Name:    Linux 
OS Version:   2.6.32-358.el6.x86_64 
Architecture:  amd64 
JVM Version:  1.7.0_40-b43 
JVM Vendor:   Oracle Corporation

7.为tomcat提供init脚本

root@tomcat2 tomcat]# vim /etc/init.d/tomcat
#!/bin/sh
# Tomcat init script for Linux. 
# 
# chkconfig: 2345 96 14 
# description: The Apache Tomcat servlet/JSP container. 
CATALINA_HOME=/usr/local/tomcat 
export CATALINA_HOME 
# export CATALINA_OPTS="-Xms128m -Xmx256m" 
exec $CATALINA_HOME/bin/catalina.sh $*

下面我们来增加执行权限

[root@tomcat ~]# chmod +x /etc/init.d/tomcat

8.测试一下

[root@tomcat2 tomcat]# service tomcat start
Using CATALINA_BASE:  /usr/local/tomcat 
Using CATALINA_HOME:  /usr/local/tomcat 
Using CATALINA_TMPDIR: /usr/local/tomcat/temp 
Using JRE_HOME:    /usr 
Using CLASSPATH:    /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar 
[root@tomcat2 tomcat]# netstat -ntulp 
Active Internet connections (only servers) 
Proto Recv-Q Send-Q Local Address        Foreign Address       State    PID/Program name
tcp    0   0 0.0.0.0:22         0.0.0.0:*          LISTEN   1042/sshd    
tcp    0   0 127.0.0.1:25        0.0.0.0:*          LISTEN   1119/master   
tcp    0   0 127.0.0.1:6010       0.0.0.0:*          LISTEN   1153/sshd    
tcp    0   0 127.0.0.1:6011       0.0.0.0:*          LISTEN   1262/sshd    
tcp    0   0 :::8080           :::*            LISTEN   1541/java    
tcp    0   0 :::22            :::*            LISTEN   1042/sshd    
tcp    0   0 ::1:25           :::*            LISTEN   1119/master   
tcp    0   0 ::1:6010          :::*            LISTEN   1153/sshd    
tcp    0   0 ::1:6011          :::*            LISTEN   1262/sshd    
tcp    0   0 ::ffff:127.0.0.1:8005    :::*            LISTEN   1541/java    
tcp    0   0 :::8009           :::*            LISTEN   1541/java

用浏览器访问 192.168.0.182:

Snip20160801_15.png

好了,大家可以看到访成功。说明我们的tomcat安装完成,下面我们来配置一下。

9.修改配置文件

[root@tomcat1 ~]# cd /usr/local/tomcat/conf/
[root@tomcat1 conf]# cp server.xml server.xml.bak
[root@tomcat1 conf]# vim server.xml


<Connector port="80" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
               
<Engine name="Catalina" defaultHost="www.test.com" jvmRoute="TomcatB">

<Host name="www.test.com"  appBase="/web"
            unpackWARs="true" autoDeploy="true">
        <Context path="" docBase="webapp" reloadable="true"/>

下面来检查一下配置文件,

[root@tomcat1 conf]# service tomcat configtest
...
INFO: Initializing ProtocolHandler ["http-nio-80"]
Aug 12, 2016 9:24:48 AM org.apache.tomcat.util.net.NioSelectorPool getSharedSelector
INFO: Using a shared selector for servlet write/read
Aug 12, 2016 9:24:48 AM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["ajp-nio-8009"]
Aug 12, 2016 9:24:48 AM org.apache.tomcat.util.net.NioSelectorPool getSharedSelector
INFO: Using a shared selector for servlet write/read
Aug 12, 2016 9:24:48 AM org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 1322 ms

创建虚拟主机文档目录并创建测试文件,

[root@tomcat1 conf]# mkdir -pv /web/webapp
mkdir: 已创建目录 "/web"
mkdir: 已创建目录 "/web/webapp"
[root@tomcat1 conf]# cd /web/webapp
[root@tomcat1 webapp]# vim index.jsp
<%@ page language="java" %>
<html>
 <head><title>TomcatB</title></head>
 <body>
 <h1><font color="blue">TomcatB </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>

下面我们来启动并测试一下,

[root@tomcat1 webapp]# service tomcat start
Using CATALINA_BASE:   /usr/local/tomcat
Using CATALINA_HOME:   /usr/local/tomcat
Using CATALINA_TMPDIR: /usr/local/tomcat/temp
Using JRE_HOME:        /usr
Using CLASSPATH:       /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar
Tomcat started.
[root@tomcat1 webapp]# ss -ntl
State       Recv-Q Send-Q              Local Address:Port                Peer Address:Port
LISTEN      0      1                ::ffff:127.0.0.1:8005                          :::*
LISTEN      0      100                            :::8009                          :::*
LISTEN      0      100                            :::80                            :::*
LISTEN      0      128                            :::22                            :::*
LISTEN      0      128                             *:22                             *:*
LISTEN      0      100                           ::1:25                            :::*
LISTEN      0      100                     127.0.0.1:25                             *:*
Snip20160812_74.png

好了,到这里我们准备工作就全部完成了,下面我们来配置tomcat的负载均衡。对了,还有个问题得说明一下。有博友会问了,你只配置了tomcat2,拓扑图中有三台机器还有两台你怎么不配置呢,是这样的由于我们实验是接着上一篇博客做的,另外两台机器的配置在上一篇博文中有,不清楚的博友参考一下http://freeloda.blog.51cto.com/2033581/1301382,我这里就不重复说明了。

三、负载均衡实现


两种方式都能实现负载均衡:

1.基于mod_proxy模块实现负载均衡
2.基于mod_jk模块实现负载均衡

下面我们就来分别演示一下,

3.1.基于mod_proxy实现负载均衡


需要的模块:

  • mod_proxy
  • HTTP, using mod_proxy_http
  • FTP, using mod_proxy_ftp
  • AJP13, using mod_proxy_ajp

至少有一种调度算法模块:

  • mod_lbmethod_byrequests
  • mod_lbmethod_bytraffic
  • mod_lbmethod_bybusyness
  • mod_lbmethod_heartbeat

以及:

  • mod_proxy_balancer

首先这些模块必须存在,其次在配置中开启它们:

查看模块:

[root@vm1 etc]# cd /usr/local/apache/modules/
[root@vm1 modules]# ls | grep mod_proxy
mod_proxy_ajp.so
mod_proxy_balancer.so
mod_proxy_connect.so
mod_proxy_express.so
mod_proxy_fcgi.so
mod_proxy_ftp.so
mod_proxy_hcheck.so
mod_proxy_http.so
mod_proxy_scgi.so
mod_proxy.so
mod_proxy_wstunnel.so

[root@vm1 modules]# ls | grep balancer
mod_proxy_balancer.so
[root@vm1 modules]# ls | grep lbmethod
mod_lbmethod_bybusyness.so
mod_lbmethod_byrequests.so
mod_lbmethod_bytraffic.so
mod_lbmethod_heartbeat.so

在配置中开启模块:

LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so
LoadModule lbmethod_bytraffic_module modules/mod_lbmethod_bytraffic.so
LoadModule lbmethod_bybusyness_module modules/mod_lbmethod_bybusyness.so
LoadModule lbmethod_heartbeat_module modules/mod_lbmethod_heartbeat.so

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_connect_module modules/mod_proxy_connect.so
LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
LoadModule proxy_scgi_module modules/mod_proxy_scgi.so
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
LoadModule proxy_express_module modules/mod_proxy_express.so
LoadModule proxy_hcheck_module modules/mod_proxy_hcheck.so

LoadModule watchdog_module modules/mod_watchdog.so

首先我们来修改一下httpd.conf配置文件,启用httpd-proxy.conf配置文

[root@apache ~]# vim /etc/httpd/httpd.conf


Include /etc/httpd/extra/httpd-proxy.conf
#Include /etc/httpd/extra/httpd-jk.conf

下面我们来修改httpd-proxy.conf配置文件,

[root@vm1 extra]# cat httpd-proxy.conf
ProxyRequests Off
<proxy balancer://lbcluster>
BalancerMember http://192.168.0.181:80 loadfactor=1 route=TomcatA
BalancerMember http://192.168.0.182:80 loadfactor=1 route=TomcatB
#ProxySet lbmethod=byrequests
ProxySet lbmethod=bytraffic
#ProxySet stickysession=JSESSIONID|jsessionid
ProxySet nofailover=On
</proxy>
<VirtualHost *:80>
ServerAdmin admin@test.com
ServerName www.test.com
ProxyPass "/" "balancer://lbcluster/"
ProxyPassReverse "/" "balancer://lbcluster/"
<Proxy *>
Require all granted
</Proxy>
<Location />
Require all granted
</Location>
</VirtualHost>

测试配置:

[root@vm1 extra]# service httpd configtest
Syntax OK

访问 192.168.0.171 测试切换:

Snip20160813_105.png
Snip20160813_106.png

测试成功!

关于如上apache指令的说明:

ProxyPreserveHost

{On|Off}:如果启用此功能,代理会将用户请求报文中的Host:行发送给后端的服务器,而不再使用ProxyPass指定的服务器地址。如果想在反向代理中支持虚拟主机,则需要开启此项,否则就无需打开此功能。

ProxyVia

{On|Off|Full|Block}:用于控制在http首部是否使用Via:,主要用于在多级代理中控制代理请求的流向。默认为Off,即不启用此功能;On表示每个请求和响应报文均添加Via:;Full表示每个Via:行都会添加当前apache服务器的版本号信息;Block表示每个代理请求报文中的Via:都会被移除。如下图,

Snip20160812_72.png

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模块在httpd 2.1的版本之后支持与后端服务器的连接池功能,连接按需创建,可以保存至连接池中以备进一步使用。连接池大小或其它设定可以通过在ProxyPass中使用key=value的方式定义。常用的key如下所示:

  • min:连接池的最小容量,此值与实际连接个数无关,仅表示连接池最小要初始化的空间大小。
  • max:连接池的最大容量,每个MPM都有自己独立的容量;值与MPM本身有关,如Prefork总是为1,而其它的则取决于ThreadsPerChild指令的值。
  • loadfactor:用于负载均衡集群配置中,定义对应后端服务器的权重,取值范围为1-100。
  • retry:当apache将请求发送至后端服务器得到错误响应时等待多长时间以后再重试。单位是秒钟。如果Proxy指定是以balancer://开头,即用于负载均衡集群时,其还可以接受一些特殊的参数,如下所示:(这些内容我们会在下一篇tomcat负载均衡集群中详细讲解)
  • lbmethod:apache实现负载均衡的调度方法,默认是byrequests,即基于权重将统计请求个数进行调度,bytraffic则执行基于权重的流量计数调度,bybusyness通过考量每个后端服务器的当前负载进行调度。
  • maxattempts:放弃请求之前实现故障转移的次数,默认为1,其最大值不应该大于总的节点数。
  • nofailover:取值为On或Off,设置为On时表示后端服务器故障时,用户的session将损坏;因此,在后端服务器不支持session复制时可将其设置为On。
  • stickysession:调度器的sticky session的名字,根据web程序语言的不同,其值为JSESSIONID或PHPSESSIONID。

上述指令除了可使用ProxySet指令直接进行设置,也能在banlancer://或ProxyPass中设定之外,具体参考:

http://httpd.apache.org/docs/2.4/mod/mod_proxy.html#proxypass
http://httpd.apache.org/docs/2.4/mod/mod_proxy_balancer.html

ProxyPassReverse

对 HTTP 响应报文的 URL 进行调整。

用于让 apache 调整HTTP重定向响应报文中的Location、Content-Location及URI首部字段所对应的URL,在反向代理环境中必须使用此指令避免重定向报文绕过proxy服务器。因为 HTTP 重定向到了后端服务器,而后端服务器应该隐藏在反向代理的后面,应该对用户不可见。可参考:

http://httpd.apache.org/docs/2.4/mod/mod_proxy.html#proxypassreverse

3.2.基于mod_jk实现负载均衡


说明:
为了避免用户直接访问后端Tomcat实例,影响负载均衡的效果,建议在Tomcat 7的各实例上禁用HTTP/1.1连接器。

为每一个Tomcat 7实例的引擎添加jvmRoute参数,并通过其为当前引擎设置全局惟一标识符。如下所示。需要注意的是,每一个实例的jvmRoute的值均不能相同。

<Engine name="Catalina" defaultHost="www.test.com" jvmRoute="TomcatA">

<Engine name="Catalina" defaultHost="www.test.com" jvmRoute="TomcatB">

同样的首先来修改httpd.conf配置文件,

[root@apache ~]# vim /etc/httpd/httpd.conf
#启用httpd-jk.conf

#Include /etc/httpd/extra/httpd-proxy.conf
Include /etc/httpd/extra/httpd-jk.conf

下面我们来修改一下httpd-jk.conf配置文件,

[root@apache ~]# vim /etc/httpd/extra/httpd-jk.conf
LoadModule jk_module modules/mod_jk.so #加载mod_jk模块
JkWorkersFile /etc/httpd/extra/workers.properties #配置文件位置 
JkLogFile logs/mod_jk.log #日志 
JkLogLevel debug #日志级别 
JkMount /* lbcluster #负载均衡器名称 
JkMount /jkstatus/ stat1 #状态信息

接下来,编辑/etc/httpd/extra/workers.properties,添加如下内容:

[root@apache ~]# vim /etc/httpd/extra/workers.properties
worker.list = lbcluster,stat1 #列表信息
worker.TomcatA.type = ajp13 #支持ajp协议 
worker.TomcatA.host = 192.168.0.181 #TomcatA实例IP
worker.TomcatA.port = 8009 #TomcatA实例端口号 
worker.TomcatA.lbfactor = 1 #负载均衡权重为1 
worker.TomcatB.type = ajp13 
worker.TomcatB.host = 192.168.0.182 
worker.TomcatB.port = 8009 
worker.TomcatB.lbfactor = 1 
worker.lbcluster.type = lb #负载均衡work,lb内置的类 
worker.lbcluster.sticky_session = 0 #会话是否绑定 
worker.lbcluster.balance_workers = TomcatA, TomcatB #TomcatA, TomcatB 集群中的实列 
worker.stat1.type = status #状态信息

测试一下配置正确性:

[root@vm1 extra]# service httpd configtest
Syntax OK

访问测试:

Snip20160813_108.png
Snip20160813_110.png

测试成功!

再说明一下配置:

workers.properties文件一般由两类指令组成:一是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.TomcatA.host=172.16.100.1

根据其工作机制的不同,worker有多种不同的类型,这是需要为每个worker定义的一项属性worker.<work name>.type。常见的类型如下:

  • ajp13:此类型表示当前worker为一个运行着的Tomcat实例。
  • lb:lb即load balancing,专用于负载均衡场景中的woker;此worker并不真正负责处理用户请求,而是将用户请求调度给其它类型为ajp13的worker。
  • status:用户显示分布式环境中各实际worker工作状态的特殊worker,它不处理任何请求,也不关联到任何实际工作的worker实例。具体示例如请参见后文中的配置。
  • worker其它常见的属性说明:
  • host:Tomcat 7的worker实例所在的主机;
  • port:Tomcat 7实例上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定义此属性;
  • 另外,在负载均衡模式中,专用的属性还有:(这些内容我们会在下一篇tomcat负载均衡集群中详细讲解)
  • 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。

3.3.查看两种状态信息


两种状态信息:

  • 基于mod_proxy模块状态信息
  • 基于mod_jk模块的状态信息

(1).基于mod_proxy模块状态信息

首先修改配置文件 /etc/httpd/httpd.conf:

[root@vm1 extra]# vi /etc/httpd/httpd.conf

Include /etc/httpd/extra/httpd-proxy.conf
#Include /etc/httpd/extra/httpd-jk.conf

修改 /etc/httpd/extra/httpd-proxy.conf:

[root@vm1 extra]# vi /etc/httpd/extra/httpd-proxy.conf
ProxyRequests Off
<proxy balancer://lbcluster>
    BalancerMember ajp://192.168.0.181:8009 loadfactor=1 route=TomcatA
    BalancerMember ajp://192.168.0.182:8009 loadfactor=1 route=TomcatB
    ProxySet lbmethod=byrequests
    #ProxySet lbmethod=bytraffic
    #ProxySet stickysession=JSESSIONID|jsessionid
    ProxySet nofailover=On
</proxy>
<VirtualHost *:80>
    ServerAdmin admin@test.com
    ServerName www.test.com
    ProxyPass "/" "balancer://lbcluster/"
    ProxyPassReverse "/" "balancer://lbcluster/"
    <Location /balancer-manager>
        SetHandler balancer-manager
        Proxypass !
        Require all granted
    </Location>
    <Proxy *>
        Require all granted
    </Proxy>
    <Location />
        Require all granted
    </Location>
</VirtualHost>

访问 http://192.168.0.171/balancer-manager 测试:

Snip20160813_112.png

好了,基于的mod_proxy模块状态信息已配置完成,下面我们演示一下基于mod_jk模块的状态信息。

(2).基于mod_jk模块的状态信息

首先修改httpd.conf配置文件,

[root@vm1 extra]# vi /etc/httpd/httpd.conf

#Include /etc/httpd/extra/httpd-proxy.conf
Include /etc/httpd/extra/httpd-jk.conf

重启 httpd:

[root@vm1 extra]# service httpd restart
Stopping httpd:                                            [  OK  ]
Starting httpd:                                            [  OK  ]

访问测试:http://192.168.0.171/jkstatus/

Snip20160813_113.png

好了,到这里我们状态信息查看就到这里了,下面我们来配置会话共享集群。

四、DeltaManager实现


1.会话管理

种类:

  • 标准会话管理器
  • 持久会话管理器

(1).标准会话管理器(StandardManager):

<Manager className="org.apache.catalina.session.StandardManager" 
     maxInactiveInterval="7200"/>

默认保存于 $CATALINA_HOME/work/Catalina/<hostname>/<webapp-name>/下的 SESSIONS.ser 文件中。

  • maxActiveSessions:最多允许的活动会话数量,默认为-1,表示不限制;
  • maxInactiveInterval:非活动的会话超时时长,默认为60s;
  • pathname:会话文件的保存目录;

(2).持久会话管理器(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>

每个用户的会话会被保存至directory指定的目录中的文件中,文件名为<session id>.session,并通过后台线程每隔一段时间(checkInterval参数定义,默认为60秒)检查一次超时会话。

保存至JDBCStore中的示例:

<Manager className="org.apache.catalina.session.PersistentManager" 
 saveOnRestart="true"> 
 <Store className="org.apache.catalina.session.JDBCStore" 
  driverName="com.mysql.jdbc.Driver" 
  connectionURL="jdbc:mysql://localhost:3306/mydb?user=jb;password=pw"/> 
</Manager>

2.Manager组件

Manger对象用于实现HTTP会话管理的功能,Tomcat中有5种Manger的实现:

(1).StandardManager
Tomcat6的默认会话管理器,用于非集群环境中对单个处于运行状态的Tomcat实例会话进行管理。当Tomcat关闭时,这些会话相关的数据会被写入磁盘上的一个名叫SESSION.ser的文件,并在Tomcat下次启动时读取此文件。

(2).PersistentManager
当一个会话长时间处于空闲状态时会被写入到swap会话对象,这对于内存资源比较吃紧的应用环境来说比较有用。
(3).DeltaManager
用于Tomcat集群的会话管理器,它通过将改变的会话数据同步给集群中的其它节点实现会话复制。这种实现会将所有会话的改变同步给集群中的每一个节点,也是在集群环境中用得最多的一种实现方式。

(4).BackupManager
用于Tomcat集群的会话管理器,与DeltaManager不同的是,某节点会话的改变只会同步给集群中的另一个而非所有节点。

(5).SimpleTcpReplicationManager
Tomcat4时用到的版本,过于老旧了。

3.DeltaManager具体实现过程

(1).修改server.xml配置文件

tomcat1:

<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="192.168.0.181"
                      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.MessageDispatchInterceptor"/>
          </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.ClusterSessionListener"/>
        </Cluster>

以上内容定义在Engine容器中,则表示对所有主机均启动用集群功能。如果定义在某Host中,则表示仅对此主机启用集群功能。(注,tomcat1与tomcat2都要修改!),我们这里将内容定义在 Engine 容器中。

tomcat 2:

<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="192.168.0.182"
                      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.MessageDispatchInterceptor"/>
          </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.ClusterSessionListener"/>
        </Cluster>

这里使用的是 Tomcat 8.5.4 版本,要做 session 复制,必须做以下的事情:

  • All your session attributes must implement java.io.Serializable
  • Uncomment the Cluster element in server.xml
  • If you have defined custom cluster valves, make sure you have the ReplicationValve defined as well under the Cluster element in server.xml
  • If your Tomcat instances are running on the same machine, make sure the Receiver.port attribute is unique for each instance, in most cases Tomcat is smart enough to resolve this on it's own by autodetecting available ports in the range 4000-4100
  • Make sure your web.xml has the <distributable/> element
  • If you are using mod_jk, make sure that jvmRoute attribute is set at your Engine <Engine name="Catalina" jvmRoute="node01" > and that the jvmRoute attribute value matches your worker name in workers.properties
  • Make sure that all nodes have the same time and sync with NTP service!
  • Make sure that your loadbalancer is configured for sticky session mode.

主要有几点要注意:

  • 所有启用集群功能的web应用程序,其web.xml中都须添加<distributable/>才能实现集群功能。如果某web应用程序没有自己的web.xml,也可以通过复制默认的web.xml至其WEB-INF目录中实现。

  • 负载均衡必须配置为 sticky session 模式(我们刚才为了掩饰切换,在两种负载均衡中都禁用了 sticky session,不过后面的测试中,发现不能开启 sticky 模式,否则不能切换,这一点不知为何)

  • 如果使用 mod_jk,配置在 Engine 元素中配置 jvmRoute 属性,这个已经配置了

  • 集群时间同步

(2).修改web.xml

tomcat1:

[root@tomcat1 ~]# cd /web/webapp/
[root@tomcat1 webapp]# ls 
index.jsp 
[root@tomcat1 webapp]# mkdir WEB-INF 
[root@tomcat1 webapp]# ls 
index.jsp WEB-INF 
[root@tomcat1 webapp]# cp /usr/local/tomcat/conf/web.xml WEB-INF/
[root@tomcat1 ~]# vim /usr/local/tomcat/conf/web.xml

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
  version="3.1">

<distributable/>

tomcat2:

同上

测试配置,重启 tomcat:

service tomcat configtest
service tomcat start

现在我们使用的还是 mod-jk 负载均衡,复习一下这个:

sticky_session:在将某请求调度至某worker后,源于此址的所有后续请求都将直接调度至此worker,实现将用户session与某worker绑定。默认为值为1,即启用此功能。如果后端的各worker之间支持session复制,则可以将此属性值设为0。

我们是设为的0,所以可以直接测试:

Snip20160813_114.png
Snip20160813_115.png

大家可以从图中看到,不管你怎么刷新SessionID都不会变,说明我们的Tomcat的DeltaManager集群配置完成,实现了多台主机之间会话共享。

再来试试 mod_proxy 负载均衡,配置如前,

[root@vm1 extra]# vi /etc/httpd/httpd.conf
Include /etc/httpd/extra/httpd-proxy.conf
#Include /etc/httpd/extra/httpd-jk.conf

[root@vm1 extra]# vi /etc/httpd/extra/httpd-proxy.conf
ProxyRequests Off
<proxy balancer://lbcluster>
    BalancerMember ajp://192.168.0.181:8009 loadfactor=1 route=TomcatA
    BalancerMember ajp://192.168.0.182:8009 loadfactor=1 route=TomcatB
    ProxySet lbmethod=byrequests
    #ProxySet lbmethod=bytraffic
    #ProxySet stickysession=JSESSIONID|jsessionid # 不能开启,一旦开启,则不能实现均衡效果
    ProxySet nofailover=On
</proxy>
<VirtualHost *:80>
    ServerAdmin admin@test.com
    ServerName www.test.com
    ProxyPass "/" "balancer://lbcluster/"
    ProxyPassReverse "/" "balancer://lbcluster/"
    <Location /balancer-manager>
        SetHandler balancer-manager
        Proxypass !
        Require all granted
    </Location>
    <Proxy *>
        Require all granted
    </Proxy>
    <Location />
        Require all granted
    </Location>
</VirtualHost>


[root@vm1 extra]# service httpd restart
Stopping httpd:                                            [  OK  ]
Starting httpd:                                            [  OK  ]

测试访问:

Snip20160813_114.png
Snip20160813_115.png

实现了一样的效果,sessinoID 不管怎么刷新,都不会改变。最后我们来实现一下,Nginx负载均衡Tomcat。

五、Nginx实现Tomcat负载均衡


1.实验拓扑

Nginx: 192.168.0.171
Tomcat1: 192.168.0.181
Tomcat2: 192.168.0.182

      Nginx
        |
       / \
Tomcat1  Tomcat2

2.添加 nginx.repo,使用 yum 安装 nginx:

[root@vm1 ~]# vi /etc/yum.repos.d/nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=0
enabled=1

[root@vm1 ~]# yum install nginx

Installed:
  nginx.x86_64 0:1.10.1-1.el6.ngx

3.停止httpd

[root@vm1 ~]# service httpd stop

4.配置nginx负载均衡

[root@vm1 ~]# cat /etc/nginx/conf.d/default.conf
upstream tomcat {
    server 192.168.0.181;
    server 192.168.0.182;
}
server {
    listen       80;
    server_name  localhost;

    #charset koi8-r;
    #access_log  /var/log/nginx/log/host.access.log  main;

    location / {
        #root   /usr/share/nginx/html;
        #index  index.html index.htm;
        proxy_pass http://tomcat;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}
}

5.检查配置并启动 nginx

[root@vm1 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@vm1 ~]# service nginx start
Starting nginx:                                            [  OK  ]
[root@vm1 ~]# ss -ntl
State      Recv-Q Send-Q          Local Address:Port            Peer Address:Port
LISTEN     0      128                         *:80                         *:*
LISTEN     0      128                        :::22                        :::*
LISTEN     0      128                         *:22                         *:*
LISTEN     0      100                       ::1:25                        :::*
LISTEN     0      100                 127.0.0.1:25                         *:*

6.进行测试

Snip20160813_114.png
Snip20160813_115.png

好了,到这里Nginx实现tomcat的负载均衡与会话共享配置完成。最后,希望大家有所收获吧,_……

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容