tomcat是一个servlet和jsp容器,可以解析java程序,所以web网站后台需要解析java的一些动态网页代码时,就需要在后台使用tomcat服务来处理。这里使用nginx,httpd和haproxy代理服务器分别加上tomcat节点做集群,然后使用两种方式来保持集群的session。
集群
1.实验环境
- 代理服务器为172.16.200.102,centos6.9
- 节点服务器1为172.16.200.103,centos6.9
- 节点服务器2为172.16.200.104,centos6.9
2.节点服务器安装tomcat:
tomcat 是基于java虚拟机运行的,所以要安装tomcat就要先安装java环境,这里安装java-1.8.0-openjdk-devel.x86_64,其他的组件就有依赖关系一起安装了
[root@localhost ~]# yum -y install java-1.8.0-openjdk-devel
安装完成后需要设置java的环境变量
[root@localhost ~]# which java #查看java程序位置
/usr/bin/java
[root@localhost ~]# vim /etc/profile.d/java.sh
export JAVA_HOME=/usr/bin/java
export PATH=$JAVA_HOME:$PATH
[root@localhost ~]# . /etc/profile.d/java.sh
[root@localhost ~]# echo $PATH
/usr/bin/java:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
安装tomcat
[root@localhost ~]# yum -y install tomcat tomcat-lib tomcat-admi
n-webapps tomcat-docs-webapp tomcat-webapps
安装完成后,我们就可以去冷部署一个测试程序了(tomcat和httpd不同,不能直接将动态程序放到web的默认路径下就可以使用,因为java代码都是类文件,可能还依赖于类库中的其他文件,需要使用类加载加载完成后才会运行。就是每个程序都是单独管理的,所以tomcat的每个应用程序目录都有固定的格式,所以我们需要先将目录创建出来):
[root@localhost tomcat]# mkdir -p /usr/share/tomcat/webapps/te
st/{class,lib,WEB-INF}
[root@localhost tomcat]# vim /usr/share/tomcat/webapps/test/in
dex.jsp #创建一个主页文件,加入以下测试内容
<%@ page language="java" %>
<html>
<head><title>TomcatA</title></head>
<body>
<h1><font color="red">TomcatA.magedu.com</font></h1>
<table align="centre" border="1">
<tr>
<td>Session ID</td>
<% session.setAttribute("magedu.com","magedu.com"); %>
<td><%= session.getId() %></td>
</tr>
<tr>
<td>Created on</td>
<td><%= session.getCreationTime() %></td>
</tr>
</table>
</body>
</html>
然后去启动tomcat
[root@localhost tomcat]# systemctl start tomcat
启动完成后用浏览器访问这个程序的测试页,在浏览器中输入http://172.16.200.103:8080,因为tomcat默认监听的地址为8080端口
在节点2服务器上同样执行上述步骤,不过测试页面改为蓝色的,这样方便分辨两台节点服务器:
<%@ page language="java" %>
<html>
<head><title>TomcatB</title></head>
<body>
<h1><font color="blue">TomcatB.magedu.com</font></h1>
<table align="centre" border="1">
<tr>
<td>Session ID</td>
<% session.setAttribute("magedu.com","magedu.com"); %>
<td><%= session.getId() %></td>
</tr>
<tr>
<td>Created on</td>
<td><%= session.getCreationTime() %></td>
</tr>
</table>
</body>
</html>
3.代理服务器配置
在172.16.200.102服务器中:
(1)我们先使用haproxy作为前端代理服务器
[root@localhost nginx]# yum -y install haproxy
[root@localhost nginx]# vim /etc/haproxy/haproxy.cfg
# 我们先在尾行模式中将frontend之后的行注释掉,将光标放到frontend main *:5000行处,进入尾行模式,输入 .,$s/^[^#]/#&/ 将没有#号的行之前加上#号,然后加入以下内容
frontend tom #定义前端
bind *:80
default_backend webapp #默认后端服务器
backend webapp
balance roundrobin #使用轮询算法
#
server app1 172.16.200.103:8080 check #定义两个节点,都使用健康检测
server app2 172.16.200.104:8080 check
[root@localhost nginx]# service haproxy start
启动完服务后,在浏览器输入http://172.16.200.102/test ,一直刷新,红蓝两个页面交替出现证明代理成功
(2)使用httpd作为前端代理服务器
[root@localhost nginx]# service stop haproxy #先将haproxy服务关闭
[root@localhost nginx]# yum -y install httpd
[root@localhost nginx]# vim /etc/httpd/conf.d/tom.conf
#定义分组
<proxy balancer://tcsrvs>
BalancerMember http://172.16.200.103:8080
BalancerMember http://172.16.200.104:8080
ProxySet lbmethod=byrequests
</Proxy>
#定义虚拟机并使用分组
<VirtualHost *:80>
ServerName www.feng.com
ProxyVia On
ProxyRequests Off
ProxyPreserveHost On
<Proxy *>
Require all granted
</Proxy>
ProxyPass / balancer://tcsrvs/
ProxyPassReverse / balancer://tcsrvs/
<Location />
Require all granted
</Location>
</VirtualHost>
[root@localhost nginx]# service httpd start
浏览器访问http://172.16.200.102/test,不断刷新,红蓝交替证明代理成功。如果没有成功,可以尝试将配置文件中的Require all granted注释掉再次尝试,这个原因是版本问题。
(3)使用nginx 作为前端代理服务器
[root@localhost nginx]# service httpd stop #先关闭httpd服务
[root@localhost nginx]# yum -y install nginx #安装nginx
[root@localhost nginx]# vim /etc/nginx/nginx.conf #到主配置文件中,在http上下文中,添加以下内容
upstream webapp {
server 172.16.200.103:8080;
server 172.16.200.104:8080;
} #定义一个7层的分组,由于tomcat监听的是8080端口,所以,这里要加上8080
[root@localhost nginx]# vim /etc/nginx/conf.d/default.conf
listen 80;
listen [::]:80; #将这两行的default删除
[root@localhost nginx]# vim /etc/nginx/conf.d/tom.conf
server {
listen 80 default;
server_name www.feng.com;
index index.jsp index.html;
location / {
proxy_pass http://webapp;
}
}
[root@localhost nginx]# nginx -t
[root@localhost nginx]# nginx -s reload
完成后浏览器访问http://172.16.200.102/test/,刷新,出现蓝色红色交替出现,代理成功。
session保持
sessionv保持有几种方法:
- 1.使用会话粘性的方式,代理服务器通过指定定的目标,将访问同一目标的请求每次都访问同一台节点服务器,达到session保持的效果。常用的有通过源地址,通过给客户端设置session首部,通过访问的url来实现。
- 2.使用会话同步的方式将每个节点的会话复制到别的节点中,这样客户端访问每个节点,都有自己的session了,这种方式在集群中节点多的情况下,会严重浪费资源,导致服务器崩溃,所以只能用在小型集群环境中
- 3.使用session server,将用户的session放到一台专门存储session的服务器中,这里我们使用memcached服务来作为session服务器。这种方式的弊端在于如果session服务器只有一台,那就成了单点,所以要使用两台或以上的session服务器,不过memcached服务在集群中使用的是旁挂式工作模式,自己没有主从的功能,只能通过节点服务器将session一起写入不同的session服务器中。
下面我们来分别实现三种session保持方式
1.会话粘性
(1)haproxy做会话粘性
先关闭之前实验的nginx服务
[root@localhost httpd]# service nginx stop
在haproxy主配置文件/etc/haproxy/haproxy.cfg中做修改,如下,增加cookie行,然后在server行最后加上cookie识别信息,通常和节点名字一样就好,以便识别.
backend webapp
balance roundrobin
cookie SRV insert indirect
server app1 172.16.200.103:8080 check cookie app1
server app2 172.16.200.104:8080 check cookie app2
完成后重启haproxy,再次访问http://172.16.200.102/test,刷新也只会出现一个页面了。
(2)httpd做会话粘性
关闭haproxy
在/etc/http/conf.d/tom.conf中修改,如下
Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED #添加cookie首部
<proxy balancer://tcsrvs>
BalancerMember http://172.16.200.103:8080 route=tomcatA loadfactor=1 #在这行两行之后添加route 和loadfactor
BalancerMember http://172.16.200.104:8080 route=tomcatB loadfactor=2
ProxySet lbmethod=byrequests
ProxySet stickysession=ROUTEID #设置会话粘性目标
设置完成后重启httpd服务,然后测试,刷新看到页面没有改变。
(3)nginx做会话粘性
先关闭httpd
在nginx主配置文件/etc/nginx/nginx.conf中修改,在upstream上下文中添加调度算法(不添加默认是轮询),如下
upstream webapp {
server 172.16.200.103:8080;
server 172.16.200.104:8080;
hash $request_uri consistent; #添加这一行,使用请求的uri为目标来做会话粘性,consistent是一致性哈希算法,不加的话只是hash表示静态数组法,也叫做取模法。
}
完成后重启nginx,测试,刷新也不会改变页面了。
2.session同步
session同步是在节点中设置的,我们先将之前实验的会话粘性取消掉,这里就使用最后一个测试的nginx服务来做第二个方法的前端代理服务器,在/etc/nginx/nginx.conf中将调度算法hash $request_uri consistent;
这行注释掉,然后重载nginx,就又回到轮询算法了,然后接可以接着搞我们的session同步实验了。
步骤:
在172.16.200.103和104中:
(1)在主配置文件中添加每台主机的标识
[root@localhost webapps]# vim /etc/tomcat/server.xml
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tcA"> #在这一行之后添加jvmRoute="tcA"
#然后在下边添加会话集群的配置
<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.16.0.4"
port="45564"
frequency="500"
dropTime="3000"/>
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="172.16.200.103"
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>
然后添加test测试程序的web.xml文件,并修改
[root@localhost webapps]# cd /usr/share/tomcat/webapps/test/WEB-INF/
[root@localhost WEB-INF]# cp /etc/tomcat/web.xml .
[root@localhost WEB-INF]# vim web.xml
#在web app段中找个位置添加如下内容
<distributable/>
注意172.16.200.103和172.16.200.104中的Receiver 段的address要写的是本机的ip,两台主机是不一样的,注意改一下
完成后重启tomcat,然后就可以验证了,我们在/var/log/tomcat/catalina./var/log/tomcat/catalina.日期.log
日志文件中可以看到一条提示信息:
INFO: Replication member added:org.apache.catalina.tribes.membership.MemberImpl[tcp://{172, 16, 200, 104}:4000,{172, 16, 200, 104},400
0, alive=1026, securePort=-1, UDP Port=-1, id={-25 -69 35 46 -118 -31 64 -88 -66 -113 -103 45 -113 -88 -40 -107 }, payload={}, command={}, domain={}, ]
看到这条信息就证明一个节点收到另外一个节点启动的信息了,证明实验成功。当然,我们也可以用浏览器访问172.16.200.102这个前端主机,刷新,然后发现后端节点会变,但是session的编号没有改变,这样也表示实验成功了。
3.使用session server来保持会话,这里我们使用memcached当作session server.
实验之前我们先将前一个实验的Tomcat Session Replication Cluster注释掉(就是上个实验中会话集群配置,在/etc/tomc),然后重启tomcat,确保之前的实验不会影响这个实验的结果
步骤:
我们在两台节点上安装memcached,这样可以少开两台虚拟机,节省资源,可以把这两个memcached服务想象成是安装在独立的服务器上就行。
(1)在两个节点上安装memcached:
[root@localhost WEB-INF]# yum -y install memcached
(2)下载需要的资源
到http://code.google.com/p/memcached-session-manager/, https://github.com/magro/memcached-session-manager这个github托管地址中下载如下包:
memcached-session-manager-${version}.jar
memcached-session-manager-tc${6,7,8}-${version}.jar #这个是tomcat是什么版本就下载什么版本
spymemcached-${version}.jar
msm-javolution-serializer-${version}.jar
javolution-${version}.jar
将下载出来的资源放到tomcat的lib目录中/usr/share/java/tomcat
(3)在两台节点的主配置文件中要测试的主机添加如下内容:
<Context path="/test" docBase="/usr/local/tomcat/webapps/test" reloadable="true">
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="n1:172.16.100.9:11211,n2:172.16.100.10:11211"
failoverNodes="n1"
requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.javolution.JavolutionTranscoderFactory"
/>
</Context>
然后重启tomcat,测试,访问172.16.200.102/test,然后刷新,发现红蓝两个页面交替出现,但是session ID不变,实验成功