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" "\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 服务器之间不支持同步数据,可以通过第三方工具进行分布式写入(magent)

Tomcat之session解决方案的更多相关文章

  1. Apache shiro集群实现 (六)分布式集群系统下的高可用session解决方案---Session共享

    Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...

  2. Apache shiro集群实现 (五)分布式集群系统下的高可用session解决方案

    Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...

  3. 负载均衡集群中的session解决方案【转】

    通常面临的问题 从用户端来解释,就是当一个用户第一次访问被负载均衡代理到后端服务器A并登录后,服务器A上保留了用户的登录信息:当用户再次发送请求时, 根据负载均衡策略可能被代理到后端不同的服务器,例如 ...

  4. 配置tomcat的session共享

    可通过下面方法限制一个用户访问一个服务器之后就只在该服务器上操作. 请求负载过程中会话信息不能丢失.那么在多个tomcat中session需要共享. 配置tomcat的session共享可以有三种解决 ...

  5. 负载均衡集群中的session解决方案

    前言 在我们给Web站点使用负载均衡之后,必须面临的一个重要问题就是Session的处理办法,无论是PHP.Python.Ruby还是Java,只要使用服务器保存Session,在做负载均衡时都需要考 ...

  6. 集群-Session解决方案

    在集群中session安全和同步是个最大的问题,下面是收集到的几种session同步的方案,希望能通过分析其各自的优劣找出其适应的场景. 1. 客户端cookie加密 简单,高效.比较好的方法是自己采 ...

  7. tomcat中session在两个webapp中实现共享

    现在遇到一个需求就是要求完成简单的单点登录,通过在一个tomcat实例中放置两个webapps应用ROOT应用和CEO应用来完成在ROOT应用登录后,在CEO可以直接使用,而未在ROOT应用登录时,不 ...

  8. 细说tomcat之session持久化探秘

    业务场景:通常,我们会在会话级别存放一些参数,期望在session生命周期内,可以一直取得保存在session中的指定数据:而只要session过期或者失效,则需要执行重新登录等操作.但是!我们对于这 ...

  9. 针对负载均衡集群中的session解决方案的总结

    在日常运维工作中,当给Web站点使用负载均衡之后,必须面临的一个重要问题就是Session的处理办法,无论是PHP.Python.Ruby还是Java语言环境,只要使用服务器保存Session,在做负 ...

随机推荐

  1. 代理IP爬取和验证(快代理&西刺代理)

    前言 仅仅伪装网页agent是不够的,你还需要一点新东西 今天主要讲解两个比较知名的国内免费IP代理网站:西刺代理&快代理,我们主要的目标是爬取其免费的高匿代理,这些IP有两大特点:免费,不稳 ...

  2. laravel容器类make方法解释

    容器类调用make方法时,如果没有已注册的key,那么会自动通过反射类实例化具体类 make /** * Resolve the given type from the container. * * ...

  3. iOS面霸计划(难度)

    一.面试题 1.Xcode项目的目录结构是怎么分组的? 2.简单介绍下在真机上调试开发证书申请流程. 3.按Home键时,怎么保存程序运行状态 4.当程序运行过程中,按下home键以后,ios程序会调 ...

  4. 基于Visual Studio Code搭建Vue开发环境

    安装node.js最新版 这里安装的是8.11.4版   image.png 更新npm至最新版 安装node.js后, npm默认版本为: 6.1.0   image.png 使用npm insta ...

  5. ubuntu 12.04 下LVS的一些搭建心得和资料整理

    最近项目上需要使用到IPVS进行负载均衡,针对外部传来的HTTP请求,分摊到多台服务器上进行处理,所以看了一下这方面的资料,在这里纪录一下. Lvs是基于IP层和内容分发请求的负载均衡方法(所以也可以 ...

  6. 斑马打印机ZBL语言

    ZBL手册:https://pan.baidu.com/s/1I8DaMUlf-9ytUwqtURw8rw 下面是打印CODE128条形码的代码 ^XA^FO100,100^BY6          ...

  7. 成为java架构师的技能

    0: 数据结构算法 数组.链表.堆.栈.队列.Hash表.二叉树等; 算法思想:递推.递归.穷举.贪心.分治.动态规划.迭代.分枝界限; 排序查找 B+/B-数.红黑树.图等; 图的深度优先搜索.图的 ...

  8. Ctrl+Tab

    很好用的快捷键. 可以在浏览器中自由切换,也可以在编辑器中自由切换.

  9. java源码 -- AbstractMap

    AbstractMap抽象类实现了一些简单且通用的方法,本身并不难.但在这个抽象类中有两个方法非常值得关注,keySet和values方法源码的实现可以值的学习. 抽象类通常作为一种骨架实现,为各自子 ...

  10. DRF图片路径问题的解决方法,网上爬取的图片放到ImageFiled自动带上域名

    由于博客园不支持markdown,推荐下面的url访问 原创url: https://blog.csdn.net/weixin_42495873/article/details/89440437 - ...