什么是会话保持
会话是指一个终端用户与交互系统进行通讯的过程,比如从输入账户密码进入操作系统到退出操作系统就是一个会话过程。会话较多用于网络上,TCP的三次握手就创建了一个会话,TCP关闭连接就是关闭会话。
Http协议是一种无状态协议,所以需要使用Session机制来保存用户的状态,比如登录状态、常用信息等。
Session用于保存一次会话的相关信息,可以实现在多个页面之间共享这些数据。
例如:你打开淘宝登录了个人账号,即使你浏览了再多的店铺宝贝,切换了很多的页面,用户名是不变的,这个就是Session起的作用。直到你关闭浏览器,Session被销毁,才会清除掉之前的登录记录。
今天和大家分享“Nginx+tomcat实现负载均衡的会话保持”就是实现:如果网站某个负载节点挂掉,请求被分配到新节点Session也会同步过来,实现会话保持,由此保证用户无感知的浏览。
实现原理
- 使用Manager对象实现HTTP会话管理
- DeltaManager作为会话管理器
- 用户访问nginx,nginx负载均衡到tomcat,用于Tomcat集群的会话管理器,将所有session会话的改变同步给集群中的每一个节点,实现会话复制。
实验配置
Nginx配置
测试环境单台服务器开了两个tomcat,一台对应8080端口,另一台对应8090端口。
创建TomcatA TomcatB,分别配置tomcat server.xml
复制以下内容到 Engine下
添加此模块:
<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.224.145"
port="4001"
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>
- 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.
备注:
1.classname配置tomcat集群在进行信息传递时互相使用什么类来进行传递
- channelsendoptions可以设置为2,4,8.10
- 2-确认发送 4-同步发送 8-异步发送
- 10-在异步模式下,可以通过加上确认发送(Acknowledge)来提高可靠性
2.manager决定如何管理集群的session信息
- className-指定实现org.apache.catalina.ha.ClusterManager接口的类,用于信息之间的管理.
- expireSessionsOnShutdown-设置为true时,一个节点关闭,将导致集群下的所有Session失效
- notifyListenersOnReplication-集群下节点间的Session复制、删除操作,是否通知session listeners
3.Channel是Tomcat节点之间进行通讯的工具。
- Channel包括5个组件:Membership、Receiver、Sender、Transport、Interceptor
4.Membership维护集群的可用节点列表。用于检测新增节点及掉线节点
- address-组播地址(任意定义组播地址),如果需要阿里云ECS部署tomcat,因为ECS不支持组播,建议改用memcache或redis存储session实现会话保持
- port-组播端口 (两个tomcat组播端口要一致)
- frequency-发送心跳(向组播地址发送UDP数据包)的时间间隔(单位:ms)。默认值为500
- dropTime-Membership在dropTime(单位:ms)内未收到某一节点的心跳,则将该节点从可用节点列表删除。默认值为3000
5.Receiver : 接收器
- address-接收消息的地址(默认auto,但是在虚拟机上开启tomcat会报错,建议配置本机IP地址)
- port-接收消息的端口(如果在一台服务器配置多个tomcat,需区分开端口)
- autoBind-端口的变化区间
如果port为4000,autoBind为100,接收器将在4000-4099间取一个端口,进行监听
- selectorTimeout-NioReceiver 轮询超时时间
- maxThreads-线程池的***线程数
6.sender:发送器负责发送消息
<Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
</Channel>
- 1.
- 2.
- 3.
7.Valve :过滤器
8.Deployer:同步集群下的所有节点的一致性
9.ClusterListener : 监听器,监听Cluster组件接收的消息,使用DeltaManager时,Cluster接收的信息通过ClusterSessionListener传递给DeltaManager
配置web.xml
在web.xml中添加属性,用于告诉web容器,该项目属于分布式项目
会话保持验证
webapps/ROOT/index.jsp 创建测试页面获取sessionID
tomcatA
<%@ 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("TomcatA","TomcatA"); %>
<td><%= session.getId() %></td>
</tr>
<tr>
<td>Created on</td>
<td><%= session.getCreationTime() %></td>
</tr>
</table>
</body>
</html>
tomcatB
<%@ page language="java" %>
<html>
<head><title>TomcatB</title></head>
<body>
<h1><font color="red">TomcatB</font></h1>
<table align="centre" border="1">
<tr>
<td>Session ID</td>
<% session.setAttribute("TomcatB","TomcatB"); %>
<td><%= session.getId() %></td>
</tr>
<tr>
<td>Created on</td>
<td><%= session.getCreationTime() %></td>
</tr>
</table>
</body>
</html>
- 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.
- 35.
- 36.
- 37.
- 38.
浏览器访问验证
总结:
tomcat实现会话保持有多种实现方式,这里只介绍了Manager对象实现,优点是利用tomcat自身集群session复制实现会话保持配置方便,缺点是像阿里云ECS这种不支持组播就无法用这种方式实现了。也可以使用memcache或redis存储session会话,但这个要下载tomcat版本相对应的memcache jar包。