拓扑图
IP网络规划
nginx | 172.17.10.150 |
tomcatA | 172.17.10.168 |
tomcatB | 172.17.10.169 |
访问原理
用户访问nginx客户端,nginx通过反向代理功能,把.jsp和.do后缀的请求发送到后端的tomcat集群,后端的tomcat集群会话session复制,从而实现会话保持功能。
nginx配置文件
user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
error_log /var/log/nginx/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 65535;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
#keepalive_timeout 0;
keepalive_timeout 65;
gzip on;
upstream tomcat-cluster {
# ip_hash
server 172.17.10.168:8080 weight=1;
server 172.17.10.169:8080 weight=1;
}
server {
listen 80;
server_name xiaomi.mage.com;
root /data/xiaomi;
#charset koi8-r;
#access_log logs/host.access.log main;
# if ($http_user_agent ~ "WOW64") {
# rewrite ^(.*)$ /404.html break;
# }
location ~* \.(jsp|do)$ {
proxy_pass http://tomcat-cluster;
}
location / {
index index.jsp index.php index.html index.htm;
}
location /status{
stub_status on;
auth_basic "status AH";
auth_basic_user_file ./htpasswd;
}
#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 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 $document_root$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;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# 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 $document_root$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;
#}
}
这样实现分离的话会出现一个问题,访问172.17.10.150/index.jsp页面如下 由于是实验环境,我们可以在nginx配置文件中server段中添加一个location,把.css和.png也代理到后端的tomcat集群,这样就能找到.css和.png文件了。(这样配置只是为了试验,如果本机有其他web服务里有以.png或者.css结尾的文件就找不到了)
location ~* \.(css|png)$ {
proxy_pass http://tomcat-cluster;
}
或者可以nginx代理端和tomcat处在一个物理机上,把root指向tomcat的工作目录也可以
root /usr/locat/tomcat/webapps/BOOT----------->tomcat默认的.jsp文件在这个目录下
后端集群实现session会话
方法一 基于集群的session复制实现(适用于小型集群)
tomcat配置文件server.xml
<Engine name="Catalina" defaultHost="localhost">
<!--For clustering, please take a look at documentation at:
/docs/cluster-howto.html (simple how to)
/docs/config/cluster.html (reference documentation) -->
<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="45565" frequency="500" dropTime="3000"/>
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver" address="172.17.10.168" 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"/>
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>
server.xml配置详解
Cluster配置:
Cluster(集群,族) 节点,如果你要配置tomcat集群,则需要使用此节点. className 表示tomcat集群时,之间相互传递信息使用那个类来实现信息 之间的传递. channelSendOptions可以设置为2、4、8、10,每个数字代表一种方式 2 = Channel.SEND_OPTIONS_USE_ACK(确认发送) 4 = Channel.SEND_OPTIONS_SYNCHRONIZED_ACK(同步发送) 8 = Channel.SEND_OPTIONS_ASYNCHRONOUS(异步发送) 在异步模式下,可以通过加上确认发送(Acknowledge)来提高可靠性,此时channelSendOptions设为10
Manager介绍
Manger对象用于实现HTTP会话管理的功能,Tomcat中有5种Manger的实现: (1).StandardManager Tomcat6的默认会话管理器,用于非集群环境中对单个处于运行状态的Tomcat实例会话 进行管理。当Tomcat关闭时,这些会话相关的数据会被写入磁盘上的一个名叫 SESSION.ser的文件,并在Tomcat下次启动时读取此文件。 (2).PersistentManager 当一个会话长时间处于空闲状态时会被写入到swap会话对象,这对于内存资源比较吃紧 的应用环境来说比较有用。 (3).DeltaManager(目前这个更适用) 用于Tomcat集群的会话管理器,它通过将改变了会话数据同步给集群中的其它节点实现 会话复制。这种实现会将所有会话的改变同步给集群中的每一个节点,也是在集群环境中 用得最多的一种实现方式。 (4).BackupManager 用于Tomcat集群的会话管理器,与DeltaManager不同的是,某节点会话的改变只会同 步给集群中的另一个而非所有节点。
Manager配置
className-指定实现org.apache.catalina.ha.ClusterManager接口的类,信息之间的管 理 expireSessionsOnShutdown-设置为true时,一个节点关闭,将导致集群下的所有 Session失效 notifyListenersOnReplication-集群下节点间的Session复制、删除操作,是否通知 session listeners
<Manager className="org.apache.catalina.ha.session.DeltaManager" expireSessionsOnShutdown="false"
notifyListenersOnReplication="true"/>
Channel介绍和配置
Channel是Tomcat节点之间进行通讯的工具。Channel包括4个组件: Membership 集群的可用节点列表 Receiver 接收器,负责接收消息 Sender 发送器,负责发送消息 Interceptor Cluster的拦截器
<Channel className="org.apache.catalina.tribes.group.GroupChannel">
Membership:维护集群的可用节点列表,它可以检查到新增的节点,也可以检查到没有心跳的节点
className-指定Membership使用的类 address-组播地址 port-组播端口 frequency-发送心跳(向组播地址发送UDP数据包)的时间间隔(单位:ms)。默认值为500 dropTime-Membership在dropTime(单位:ms)内未收到某一节点的心跳,则将该节点从可用节点列表删除。默认值为3000 注: 组播(Multicast):一个发送者和多个接收者之间实现一对多的网络连接。 一个发送者同时给多个接收者传输相同的数据,只需复制一份相同的数据包。 它提高了数据传送效率,减少了骨干网络出现拥塞的可能性 相同组播地址、端口的Tomcat节点,可以组成集群下的子集群
<Membership className="org.apache.catalina.tribes.membership.McastService"
address="228.0.0.4"
port="45564"
frequency="500"
dropTime="3000"/>
Receiver : 接收器,负责接收消息
接收器分为两种:BioReceiver(阻塞式)、NioReceiver(非阻塞式) className-指定Receiver使用的类 address-接收消息的地址 port-接收消息的端口 autoBind-端口的变化区间 如果port为4000,autoBind为100,接收器将在4000-4099间取一个端口,进行监听 selectorTimeout-NioReceiver内轮询的超时时间 maxThreads-线程池的最大线程数
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="172.17.10.168"
port="4000"
autoBind="100"
selectorTimeout="5000"
maxThreads="6"/>
(这里这个接收地址默认auto绑定的是本机的127地址,可以修改为本机桥接地址,便于通信)
Sender : 发送器,负责发送消息
Sender内嵌了Transport组件,Transport真正负责发送消息
<Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
Transport:定义传输方式 Transport分为两种:bio.PooledMultiSender(阻塞式)、nio.PooledParallelSender(非阻塞式)
<Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
</Sender>
Interceptor : Cluster的拦截器
TcpFailureDetector-网络、系统比较繁忙时,Membership可能无法及时更新可用节点列表,此时TcpFailureDetector可以拦截到某个节点关闭的信息,并尝试通过TCP连接到此节点,以确保此节点真正关闭,从而更新集群可以用节点列表
<Interceptor
className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
MessageDispatch15Interceptor-查看Cluster组件发送消息的方式是否设置为 Channel.SEND_OPTIONS_ASYNCHRONOUS(Cluster标签下的channelSendOptions为8时)。 设置为Channel.SEND_OPTIONS_ASYNCHRONOUS时, MessageDispatch15Interceptor先将等待发送的消息进行排队,然后将排好队的消息转给Sender
<Interceptor
className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
ClusterListener : 监听器,监听Cluster组件接收的消息 使用DeltaManager时,Cluster接收的信息通过ClusterSessionListener传递给DeltaManager -->
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
配置文件web.xml
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<distributable/> (在文件结尾处</web-app>上方加上这个参数就行)
</web-app>
测试页面
<%@ page language="java" %>
<html>
<head><title>TomcatA</title></head>
<body>
<font color="blue">TomcatA
<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>
如图
如果测试不通过的话,就复制tomcat配置文件conf目录下的web.xml文件到你的测试目录下的WEB-INF(需要手动创建)
这样基于tomcat集群的session复制的配置就完成了~
方法二 tomcat结合memcached实现seesion共享 (适用于比较大的集群)
环境准备
Tomcat Session Server (memcached) https://github.com/magro/memcached-session-manager 支持的session server类型: memcached: redis:
相关包
memcached-session-manager-2.1.1.jar memcached-session-manager-tc7-2.1.1.jar(注意:要根据tomcat版本下载相应的) spymemcached-2.11.1.jar msm-javolution-serializer-2.1.1.jar javolution-5.4.3.1.jar