zoukankan      html  css  js  c++  java
  • Tomcat之session解决方案

    Tomcat集群使用Memcached实现Session共享

    session方案及配置

    用户访问服务器资源主要分成两类,一类是无状态访问,例如请求一张图片。另一类是有状态访问,这种情况下,服务器需要记录追踪用户状态,并根据用户所处状态做出不同响应,典型的例子是购物车。Session的作用就是在Web服务器上保持用户的状态信息。

    用户请求连接服务器时,服务器会生成一个唯一的sessionID为标识符至用户端本地,客户端使用该sessionID来存/取服务器端的session空间。sessionID是客户端浏览器cookie保存的。

    当客户端访问Tomcat集群时,所有的请求将被Nginx拦截,由Nginx做负载均衡后转发给后台真实Tomcat。按照这个流程就可能出现一个问题,当用户进行页面刷新或跳转时,每次请求将被转发给不同的Tomcat处理,这样就会造成Session的不同步。举个简单的栗子,例如当用户往购物车添加商品时,兴高采烈地准备买单了,当他跳转到付款页面却发现购物车被清空了,这就是Session丢失的典型栗子。因此,我们需要为集群环境做Session同步。

    总结一下:session就是在一次会话中解决2次(或多次)http请求的关联,让他们产生联系,让2个(或多个)页面都能读取到这个全局的session信息,session信息存在于服务端,所以也就解决了session的问题。。而我们现在所说的session解决方案,一般是指怎么避免一台后端服务器挂掉,还能正常保持session

    session更详细详解戳这里

    单机环境下,session可有部署在服务器上的web容器如:Tomcat进行保存管理。但在使用负载均衡集群时如架构前端Nginx来负载均衡后端多台Tomcat,所以可能分发到任何一台后端的Tomcat;虽然呢,也有类似于Nginx中的ip_hash算法可以将客户端和服务器做一个绑定,但是弊端太多,生产环境慎用。

    下面将介绍几种session的方案

    一、session绑定

    session绑定就是利用负载均衡服务器的hash源IP地址算法实现,将来源于同一个IP的请求总是分发到同一台后端web服务器上,又称为会话粘滞。
    但是如果该服务器死机或故障,那该用户的session空间也就不复存在了,就如我们网页浏览购物网站时,刚添加到购物车的宝贝,一刷新全没了,用户体验肯定非常差,所以该session绑定方案使用场景非常有限

    #编辑nginx主配置文件
    upstream tomcats {
        ip_hash
    #使用ip_hash算法调度
      server 192.168.111.4:8080;
    
      server 192.168.111.5:8080;
    
      }
    

    二、session复制

    适用于小型架构的服务器集群。开启web服务器的session复制功能,在集群中的几台服务器之间同步session对象,这样每台服务器都保存了用户的session信息,但是当集群规模比较大时,session复制机制会消耗大量系统资源以及网络资源

    操作系统 IP地址 软件版本 主机名
    centos7 192.168.111.3 nginx1.14.2 Nginx
    centos7 192.168.111.4 JDK1.7;Tomcat7.0.54 tnode1
    centos7 192.168.111.5 JDK1.7;Tomcat7.0.54 tnode2

    如有防火墙或selinux记得关闭或者修改相应规则

    [root@localhost ~]# nginx -v
    nginx version: nginx/1.14.2
    
    [root@localhost ~]# vim /etc/hosts
        192.168.111.3	nginx
        192.168.111.4	tnode1
        192.168.111.5	tnode2
    
    [root@localhost ~]# scp /etc/hosts 192.168.111.4:/etc/
    [root@localhost ~]# scp /etc/hosts 192.168.111.5:/etc/
    #配置hosts文件
    
    #hostname nginx
    #hostname tnode1
    #hostname tnode2
    修改主机名
    
    
    [root@nginx ~]# vim /usr/local/nginx/conf/nginx.conf
        http {
        ...
            upstream tomcatpool {
                server 192.168.111.4:8080 weight=1 max_fails=1 fail_timeout=10s;
                server 192.168.111.5:8080 weight=1 max_fails=1 fail_timeout=10s;
                }
        #以上为添加
        location / {
                root   html;
                index  index.html index.htm;
                proxy_pass http://tomcatpool;
            }
        #以上为修改添加最下面一行调用池
    
    
    安装配置Tomcat。
    
    [root@tnode1 ~]# tar zxf jdk-7u65-linux-x64.tar.gz 
    [root@tnode1 ~]# mv jdk1.7.0_65/ /usr/local/java7
    [root@tnode1 ~]# echo "PATH=$PATH:/usr/local/java7/bin" >> /etc/profile
    [root@tnode1 ~]# source /etc/profile
    [root@tnode1 ~]# rm -rf /usr/bin/java
    [root@tnode1 ~]# java -version
    java version "1.7.0_65"
    Java(TM) SE Runtime Environment (build 1.7.0_65-b17)
    Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode)
    [root@tnode1 ~]# tar zxf apache-tomcat-7.0.54.tar.gz 
    [root@tnode1 ~]# mv apache-tomcat-7.0.54 /usr/local/tomcat7
    
    
    [root@tnode2 ~]# tar zxf jdk-7u65-linux-x64.tar.gz 
    [root@tnode2 ~]# mv jdk1.7.0_65/ /usr/local/java7
    [root@tnode2 ~]# echo "PATH=$PATH:/usr/local/java7/bin" >> /etc/profile
    [root@tnode2 ~]# source /etc/profile
    [root@tnode2 ~]# rm -rf /usr/bin/java
    [root@tnode1 ~]# java -version
    java version "1.7.0_65"
    Java(TM) SE Runtime Environment (build 1.7.0_65-b17)
    Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode)
    [root@tnode2 ~]# tar zxf apache-tomcat-7.0.54.tar.gz 
    [root@tnode2 ~]# mv apache-tomcat-7.0.54 /usr/local/tomcat7
    
    
    [root@tnode1 ~]# vim /usr/local/tomcat7/webapps/ROOT/session.jsp
    #测试页面
        Session ID:<%= session.getId() %><BR>
        SessionPort:<%= request.getServerPort() %>
        <% out.println("This tomcat server 192.168.111.4");%>
    
    
    [root@tnode2 ~]# vim /usr/local/tomcat7/webapps/ROOT/session.jsp
        Session ID:<%= session.getId() %><BR>
        SessionPort:<%= request.getServerPort() %>
        <% out.println("This tomcat server 192.168.111.5");%>
        
    #这是一个获取当前服务器所拥有的IP和sessionID的脚本页面
    
    
    
    下面开始配置session复制(生产环境时一般10台以下使用该session解决方案
    
    [root@tnode1 ~]# vim /usr/local/tomcat7/conf/server.xml 
        104     <Engine name="Catalina" defaultHost="localhost" jvmRoute="tnode1">
        #改行后面添加jvmroute配置项。
        109       <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
        #去掉注释
        
    [root@tnode1 ~]# vim /usr/local/tomcat7/webapps/ROOT/WEB-INF/web.xml 
        </description> 
        #添加至倒数第二行
    
    
    [root@tnode2 ~]# vim /usr/local/tomcat7/conf/server.xml 
        <Engine name="Catalina" defaultHost="localhost" jvmRoute="tnode2">
        <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
        
    [root@tnode1 ~]# vim /usr/local/tomcat7/webapps/ROOT/WEB-INF/web.xml 
        </description> 
        #添加至倒数第二行
    
    
    
    [root@tnode1 ~]# /usr/local/tomcat7/bin/shutdown.sh
    
    [root@tnode1 ~]# /usr/local/tomcat7/bin/startup.sh 
    
    [root@tnode2 ~]# /usr/local/tomcat7/bin/shutdown.sh 
    
    [root@tnode2 ~]# /usr/local/tomcat7/bin/startup.sh 
        
    客户端使用火狐浏览器输入:http://192.168.111.3/session.jsp来进行测试,并且刷新(别强制刷新,那样是新的sessionID)
    

    三、使用memcached解决session问题

    memcached是一套分布式的快取系统,相关数据都是在内存里,一旦服务重启或者死机,则数据必然丢失;memcached是键值对存储形式;在以下试验中,每个session都会在这两台memcached上进行分布式存储,有了冗余性,即使一台出问题也不影响工作。同样只适用于中小型架构。

    以下的配置两台Tomcat一样

    [root@tnode1 ~]# yum -y install libevent memcached
    #安装memcached及其依赖
    
    [root@tnode1 ~]# memcached -u root -m 512M -n 10 -f 2 -d -vvv -c 512
        //-u:运行用户必须是root身份
        //-m:指定使用物理机的多少内存
        //-n:chunk size的最小空间是多少字节
        //-f:chunk size大小增长的倍数默认1.25倍
        //-d:在后台启动
        //-vvv:显示详细信息
        //-c:memcached服务的最大连接数
    Tomcat连接memcached所依赖的库文件:
    javolution-5.5.1.jar                     memcached-session-manager-1.5.1.jar      msm-kryo-serializer-1.6.4.jar
    kryo-1.03.jar                            memcached-session-manager-tc7-1.5.1.jar  reflectasm-0.9.jar
    kryo-serializers-0.10.jar                minlog-1.2.jar                           spymemcached-2.7.3.jar
    memcached-2.5.jar                        msm-javolution-serializer-1.5.1.jar 
    将这些文件放到/usr/local/tomcat7/lib/目录下
    
    配置文件连接memcached。
    [root@tnode2 ~]# vim /usr/local/tomcat7/conf/context.xml 
        <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager" memcachedNodes="memA:192.168.111.4:11211 memB:192.168.111.5:11211" requestUrilgnorePattern=".*(ico|png|gif|jpg|css|js)$" transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"/>
        
    [root@tnode2 ~]# /usr/local/tomcat7/bin/shutdown.sh 
    [root@tnode2 ~]# /usr/local/tomcat7/bin/startup.sh
    #重启服务
    
    测试页仍然使用以上的那个测试页
    
    浏览器访问http://192.168.111.3/session.jsp测试,可以看到sessionID不变
    

    四、使用redis解决session问题

    注意:尽量保持系统环境的纯净

    如果使用如上做完memcached环境接着做redis
    
    1.rpm -e memcached-1...
    2.vim /usr/local/tomcat7/conf/context.xml
    3.pkill -9 memcached
    4.删除相关jar包
    
    
    
    安装部署redis
    [root@tnode1 ~]# tar zxf redis-3.2.5.tar.gz 
    [root@tnode1 ~]# yum -y install tcl
    #依赖包
    
    [root@tnode1 src]# mkdir /usr/local/redis/{bin,etc,var} -pv
    
    
    [root@tnode1 src]# cp ~/redis-3.2.5/src/redis-benchmark redis-check-aof redis-cli redis-server /usr/local/redis/bin/
    //redis-benchmark:读写性能测试工具
    //redis-cli:redis命令行操作工具
    //redis-server:redis服务的daemon启动程序
    [root@tnode1 src]# cp ~/redis-3.2.5/redis.conf /usr/local/redis/etc/
    //redis的主配置文件
    
    
    [root@tnode1 src]# vim /usr/local/redis/etc/redis.conf
        128 daemonize yes
        #表示将redis启动在后台
        
        61 bind 0.0.0.0
        #监听所有主机
    
    
    [root@tnode1 src]# /usr/local/redis/bin/redis-server /usr/local/redis/etc/redis.conf 
    [root@tnode1 src]# netstat -anpt | grep redis
    tcp        0      0 0.0.0.0:6379            0.0.0.0:*               LISTEN      69432/redis-server  
    #启动并且查看端口
    
    
    Tomcat和redis连接需要用到如下包:
    commons-logging-1.1.3.jar                jedis-2.5.2.jar                          tomcat-redis-session-manage-tomcat7.jar
    commons-pool2-2.2.jar                    tomcat-juli.jar                          
    
    [root@tnode1 ~]# vim /usr/local/tomcat7/conf/context.xml 
    #连接redis配置
    <Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />
    <Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager" host="192.168.111.4" port="6379" database="0" maxInactiveInterval="60" />
    #Context字段中添加如上,IP为redis服务器的IP。
    
    
    #如下可以先把node2上该lib目录删掉,直接复制覆盖
    [root@tnode1 ~]# scp -r /usr/local/tomcat7/lib root@192.168.111.5:/usr/local/tomcat7/lib
    
    #如下是直接覆盖node2配置文件
    [root@tnode1 ~]# scp /usr/local/tomcat7/conf/context.xml root@192.168.111.5:/usr/local/tomcat7/conf/
    
    #然后node2上重启Tomcat服务,可多重启几遍顺便观察node1上的redis监视状态,并且时刻关注本机catalina.out日志变化是否异常。
    
    
    #如下是正常情况下redis监视的状态输出
    [root@tnode1 src]# /usr/local/redis/bin/redis-cli -p 6379 monitor
    
    1556385116.932343 [0 192.168.111.4:37948] "EXPIRE" "DCF23D098140E899E20A996990F690D5" "1800"
    1556385116.970109 [0 192.168.111.4:37948] "GET" "DCF23D098140E899E20A996990F690D5"
    1556385116.972760 [0 192.168.111.4:37948] "EXPIRE" "DCF23D098140E899E20A996990F690D5" "1800"
    1556385117.582753 [0 192.168.111.4:37948] "GET" "DCF23D098140E899E20A996990F690D5"
    1556385117.584391 [0 192.168.111.4:37948] "EXPIRE" "DCF23D098140E899E20A996990F690D5" "1800"
    1556385117.599639 [0 192.168.111.4:37948] "GET" "DCF23D098140E899E20A996990F690D5"
    1556385117.600743 [0 192.168.111.4:37948] "EXPIRE" "DCF23D098140E899E20A996990F690D5" "1800"
    1556385125.008432 [0 192.168.111.4:37948] "PING"
    1556385155.006175 [0 192.168.111.4:37948] "PING"
    1556386097.450914 [0 192.168.111.5:34118] "SETNX" "F7379EF99F21FD0BBF830056FEF162A0" "null"
    1556386097.575639 [0 192.168.111.5:34118] "SET" "F7379EF99F21FD0BBF830056FEF162A0" "xacxedx00x05srx00Dcom.orangefunction.tomcat.redissessions.S
    essionSerializationMetadataBxd9xd9xf7vxa2xdbLx03x00x01[x00x15sessionAttributesHashtx00x02[Bxpwx14x00x00x00x10x1fxa2xa9ox15x7fxe1Wx9cx9cxc6xc2xb0xd5xe2xa8xsrx00x0ejava.lang.Long;x8bxe4x90xccx8f#xdfx02x00x01Jx00x05valuexrx00x10java.lang.Numberx86xacx95x1dx0bx94xe0x8bx02x00x00xpx00x00x01j3x83Fxddsqx00~x00x03x00x00x01j3x83Fxddsrx00x11java.lang.Integerx12xe2xa0xa4xf7x81x878x02x00x01Ix00x05valuexqx00~x00x04x00x00asrx00x11java.lang.Booleanxcd rx80xd5x9cxfaxeex02x00x01Zx00x05valuexpx01qx00~x00
    sqx00~x00x03x00x00x01j3x83Fxddtx00 F7379EF99F21FD0BBF830056FEF162A0sqx00~x00ax00x00x00x00wx00x00x01j3x83Fxdd"1556386097.577377 [0 192.168.111.5:34118] "EXPIRE" "F7379EF99F21FD0BBF830056FEF162A0" "1800"
    1556386097.586858 [0 192.168.111.5:34118] "EXPIRE" "F7379EF99F21FD0BBF830056FEF162A0" "1800"
    1556386099.395455 [0 192.168.111.5:34118] "GET" "F7379EF99F21FD0BBF830056FEF162A0"
    1556386099.403983 [0 192.168.111.5:34118] "EXPIRE" "F7379EF99F21FD0BBF830056FEF162A0" "1800"
    1556386099.410867 [0 192.168.111.5:34118] "GET" "F7379EF99F21FD0BBF830056FEF162A0"
    1556386099.413166 [0 192.168.111.5:34118] "EXPIRE" "F7379EF99F21FD0BBF830056FEF162A0" "1800"
    1556386099.855877 [0 192.168.111.5:34118] "GET" "F7379EF99F21FD0BBF830056FEF162A0"
    1556386099.857305 [0 192.168.111.5:34118] "EXPIRE" "F7379EF99F21FD0BBF830056FEF162A0" "1800"
    1556386100.497947 [0 192.168.111.5:34118] "GET" "F7379EF99F21FD0BBF830056FEF162A0"
    
    
    
    客户端访问http://192.168.111.3/session.jsp,是Nginx的地址来进行测试,正常时是sessionID不会变的
    
    

    五、memcached和redis对比表

    内存利用率 性能 数据持久化 高可用
    redis 键值对村存储利用率低于memcached,但使用hash结构存储则超过后者 只使用单核CPU,数据大小100K以下快于后者 支持数据持久化(保存到硬盘) Redis 支持数据的备份,即 master-slave 模式的数据备份,支持多种数据结构的存储
    memcached 如上 可以使用多核,100K以上快于前者 自身不支持持久化,但可以结合其他数据库做架构如:memcached + bdb 服务器之间不支持同步数据,可以通过第三方工具进行分布式写入(magent)
  • 相关阅读:
    B
    C. Baby Ehab Partitions Again
    NLP中数据稀疏问题的解决——数据平滑
    CodeForces-EDU-105 Div2 部分题解报告
    C
    前端面试知识点汇总
    elementUI table 合计行 单元格合并
    微信小程序 tab切换组件封装
    微信小程序-wx.request的封装实现
    微信小程序-input密码可见与不可见
  • 原文地址:https://www.cnblogs.com/jojoword/p/10843860.html
Copyright © 2011-2022 走看看