阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

Tomcat之session解决方案

168次阅读
没有评论

共计 9696 个字符,预计需要花费 25 分钟才能阅读完成。

session 方案及配置

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

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

当客户端访问 Tomcat 集群时,所有的请求将被 Nginx 拦截,由 Nginx 做负载均衡后转发给后台真实 Tomcat。按照这个流程就可能出现一个问题,当用户进行页面刷新或跳转时,每次请求将被转发给不同的 Tomcat 处理,这样就会造成 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 之 session 解决方案

以下的配置两台 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" "\xac\xed\x00\x05sr\x00Dcom.orangefunction.tomcat.redissessions.S
essionSerializationMetadataB\xd9\xd9\xf7v\xa2\xdbL\x03\x00\x01[\x00\x15sessionAttributesHasht\x00\x02[Bxpw\x14\x00\x00\x00\x10\x1f\xa2\xa9o\x15\x7f\xe1W\x9c\x9c\xc6\xc2\xb0\xd5\xe2\xa8xsr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01j3\x83F\xddsq\x00~\x00\x03\x00\x00\x01j3\x83F\xddsr\x00\x11java.lang.Integer\x12\xe2\xa0\xa4\xf7\x81\x878\x02\x00\x01I\x00\x05valuexq\x00~\x00\x04\x00\x00\a\bsr\x00\x11java.lang.Boolean\xcd r\x80\xd5\x9c\xfa\xee\x02\x00\x01Z\x00\x05valuexp\x01q\x00~\x00\nsq\x00~\x00\x03\x00\x00\x01j3\x83F\xddt\x00 F7379EF99F21FD0BBF830056FEF162A0sq\x00~\x00\a\x00\x00\x00\x00w\b\x00\x00\x01j3\x83F\xdd"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 两者性能都属于非常不错的,而且也都是开源免费。

正文完
星哥说事-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-01-21发表,共计9696字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中