Session会话保持机制的原理与Tomcat Session Cluster示例

一、Session的定义

  在计算机科学中,特别是在网络中,session是两个或更多个通信设备之间或计算机和用户之间的临时和交互式信息交换。session在某个时间点建立,然后在之后的某一时间点拆除。建立的通信session可以在每个方向上涉及多个消息。session通常是有状态的,这意味着至少一个通信部分需要保存关于会话历史的状态信息以便能够进行通信,而在无状态通信中,通信由具有响应的独立请求组成。——Wikipedia

  Session:在计算机中,尤其是在网络应用中,称为“会话控制”。Session 对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的 Web 页时,如果该用户还没有会话,则 Web 服务器将自动创建一个 Session 对象。当会话过期或被放弃后,服务器将终止该会话。Session 对象最常见的一个用法就是存储用户的首选项。例如,如果用户指明不喜欢查看图形,就可以将该信息存储在 Session 对象中。——百度

二、Session的作用与意义

  在WEB应用中,一般都是采用http协议进行通信,但http是一种无状态的通信协议,这里的无状态是指协议对于事务处理没有记忆能力,在会话结束后,服务器不知道客户端是什么状态。在http协议初期,为了保证WEB的并发访问处理能力,http协议不会保存客户端访问的任何状态信息。后来http协议中加入了keep-alive功能,这是一种会话保持机制,这样便可以将会话持续保持一段时间,当用户在这个时间段又一次访问时会提高响应速度节省资源,但keep-alive也不会记录用户的状态,只是让连接保持一段时间,当用户超过这个时间段再次访问,依然还是会当做新请求进行处理。但在WEB应用中有很多场景都需要根据用户的历史访问状态来将请求分配给后端服务器处理,例如登录记录、购物车记录,浏览记录等,用户每次访问都无法找到以前的记录是很影响用户体验的,这样就诞生了cookie和session机制。

  先来说说cookie,当用户访问www.abc.com时需要登录,因为http是无状态的,所以导致访问www.abc.com/xxx又需要重新登录,这样是很头痛的事情,cookie的出现解决了这个问题,cookie可以将用户的少量信息保存至用户客户端本地,它将www.abc.com域名作为一个全局,在用户登录此域名下的所有URI时都不需要重新登陆。但用户本地的存储大小是有限的,并且将一些私密信息储存在本地是有安全风险的。

  如何保证用户体验,又能保证安全性,这就是Session的意义,session也是一种用户状态储存机制,但与cookie不同的是,session储存在后端服务器的内存中。session在web应用中有着非常重要的意义,它可以很方便很安全的控制访问权限。

二、常见的Session会话保持方式

1.Session sticky(session会话粘性)

会话粘性是指在用户第一次访问后按一定的算法与之将其中一台后端服务器做绑定,一般分为两种:

a.souce_ip:如nginx中的ip_hash算法、LVS中的sh算法

b.cookie:HAProxy中的cookie

2.Session Cluster(session集群)

  Session Cluster是指将后端服务器组成一个集群,共享所有的session, 当某一台服务器故障后不至于影响用户体验。这种方法一般用在后端服务器较少的情况(3-4台),因为当服务器太多时会占用大量的IO,影响集群性能。

下面将以Tomcat为例介绍介绍这种session保持机制。

1.实现基础

Tomcat Session Cluster的实现是利用组播将集群中的session进行共享,这与keepalived类似。Tomcat原生就支持这种机制,所以配置起来比较简单,但不能支持太多的主机,

2.结构与IP分配

Nginx主机:IP:192.168.29.109

Tomcat主机集群:192.168.29.107、192.168.29.132、192.168.29.110

安装好Nginx和Tomcat,教程:https://www.cnblogs.com/readygood/p/9801253.html

关闭防火墙和Selinux

 1.配置Nginx

vim /etc/nginx/nginx.conf #配置主配置文件
upstream tcsv { #在http模块中插入upstream模块
    server 10.10.10.130:8080;
    server 10.10.10.131:8080;
    server 10.10.10.132:8080;
                }
vim /etc/nginx/conf.d/tomcat.conf #添加虚拟主机
server {
        listen 80;
        server_name www.ready.com;
        location  / {
                proxy_pass http://tcsv;
                }
        }

2.配置Tomcat,创建.jsp测试页

mkdir -pv /var/lib/tomcat/webapps/test/{WEB-INF,META-INF,classes,lib} #创建jsp文件所需目录
vim /var/lib/tomcat/webapps/test/index.jsp #创建jsp测试文件,功能为session ID监控
<%@ page language="java" %>
<html>
    <head><title>TomcatA</title></head>
    <body>
        <h1><font color="red">Tomcat.ready.com</font></h1> #将3台Tomcat主机配置为不同颜色,我这里分别是red、green、blue
        <table align="centre" border="1">
        <tr>
            <td>Session ID</td>
        <% session.setAttribute("ready.com","ready.com"); %>
            <td><%= session.getId() %></td>
        </tr>
            <tr>
                <td>Created on</td>
                <td><%= session.getCreationTime() %></td>
            </tr>
        </table>
    </body>
</html>

3.启动Nginx和Tomcat,并刷新页面(修改hosts添加本地解析)

不同颜色代表不同主机的响应,我们可以发现就算响应的主机相同Session ID也不同,这说明Session机制未开启(因为前端Nginx调度默认采用的rr算法),就算在同一主机访问也会被识别为不同用户。

 4.配置Tomcat Cluster服务

Tomcat原生就是支持此服务的,所以只需要在/etc/tomcat/server.xml中嵌入 <Cluster> 组件即可,要注意的是 <Cluster> 组件只能用在 <Engine> 和 <Host> 中。注意事项如下

1.默认多播地址为228.0.0.4

2.默认多播端口是45564(端口和地址一起决定集群成员。

3.广播的IP是 java.net.InetAddress.getLocalHost().getHostAddress() (确保没有广播127.0.0.1,这是一个常见的错误)

4.监听复制消息的TCP端口是范围4000-4100中的第一个可用服务器套接字

5.侦听器被配置为 ClusterSessionListener 

6.配置两个拦截器 TcpFailureDetector 和 MessageDispatch15Interceptor 

vi /etc/tomcat/server.xml
a.将下面的代码插入 <Engine> 或者 <Host> 中
<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.29.132" #填写本机IP地址,默认为auto
                      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>
b.将默认web.xml文件(/etc/tomcat/web.xml)复制到事先创建好的/usr/share/tomcat/webapps/test/WEB-INF/目录下并修改

web.xml文件是用来初始化配置信息:比如Welcome页面、servlet、servlet-mapping、filter、listener、启动加载级别等。

cp /etc/tomcat/web.xml /usr/share/tomcat/webapps/test/WEB-INF/
vim /usr/share/tomcat/webapps/test/WEB-INF/web.xml

在 <web-app> 内任意位置插入代码 <distributable/> ,其他Tomcat主机也做相同操作。

c.重启Tomcat服务,查看Tomcat状态

在日志中看到下面的信息就说明session共享配置成功:

d.刷新页面,观察session ID的变化

可以看到不管怎么刷新Session ID都保持不变,但标题颜色会变化,说明无论去前端Nginx怎么调度Session都没有发生变化。

e.注意事项

1.在插入 <Cluster> 组件时要注意 <Receiver> 中的 address= 的IP配置,尽量不要用“auto”。

2.Tomcat主机的网关一定要设置正确,不然无法发送和接收组播信息。

3.要在日志中看到类似 [tcp://{192, 168, 29, 107}:4000,{192, 168, 29, 107},4000, alive=1037 的信息才说明组播信息成功发送,也可以使用 tcpdump 命令来检查组播信息状态:

tcpdump -i ens33 -nn host 228.0.0.4

猜你喜欢

转载自www.cnblogs.com/readygood/p/9807966.html