一.为什么要Session共享

  Session存储在服务器的内存中,比如Java中,Session存放在JVM的中,Session也可以持久化到file,MySQL,redis等,SessionID存放在Cookie中。

  比如一个系统登录后,假如用户的请求通过Nginx被转发到tomcat1上,这时一些当前用户的信息放入session中,比如登录信息让用户一直处于登录状态。那么Nginx负载均衡后,可能用户刷新页面后重新跳转到了tomcat2,而tomcat2上没有Session,系统就会要求用户再次去登录,这样明显会给用户带来不好的体验。

二.session共享解决方案(Java)

  1.tomcat可以直接配置

<!-- 第1步:修改server.xml,在Host节点下添加如下Cluster节点 -->
<!-- 用于Session复制 -->
<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" />
<!-- 这里如果启动出现异常,则可以尝试把address中的"auto"改为"localhost" -->
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver" address="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.MessageDispatchInterceptor" />
</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.ClusterSessionListener" />
</Cluster>
<!-- 第2步:在web.xml中添加如下节点 -->
<!-- 用于Session复制 -->
<distributable/>

  2.使用token重写Session

    这里token是JSON Web Token,一般用它来替换掉Session实现数据共享(共享token?)

  3.使用Cookie的方式

    这个方式原理是将系统用户的Session信息加密、序列化后以Cookie的方式, 统一 种植在根域名下(如:.host.com),利用浏览器访问该根域名下的所有二级域名站点时,会传递与之域名对应的所有Cookie内容的特性,从而实现 用户的Cookie化Session 在多服务间的共享访问。

    这个方案的优点无需额外的服务器资源;缺点是由于受http协议头信心长度的限制,仅能够存储小部分的用户信息,同时Cookie化的 Session内容需要进行安全加解密(如:采用DES、RSA等进行明文加解密;再由MD5、SHA-1等算法进行防伪认证),另外它也会占用一定的带宽资源,因为浏览器会在请求当前域名下任何资源时将本地Cookie附加在http头中传递到服务器,最重要的是存在安全隐患。

  4.使用Nginx中的ip绑定方式

    这个只需要在Nginx中简单配置一句 ip_hash; 就可以了,但是该方式的缺点也很明显。具体可以参考的的上一篇博客 https://www.cnblogs.com/ywb-articles/p/10686673.html

  5.基于数据库的Session共享

    以为MySQL为例,每次将session数据存到数据库中。这个方案还是比较可行的,不少开发者使用了这种方式。但它的缺点在于Session的并发读写能力取决于MySQL数据库的性能,对数据库的压力大,同时需要自己实现Session淘汰逻辑,以便定时从数据表中更新、删除 Session记录,当并发过高时容易出现表锁,虽然可以选择行级锁的表引擎,但很多时候这个方案不是最优方案。

  6.使用redis的方式(Spring Session + redis实现,也可以是其他NoSQL)(推荐)

    该方式配置简单,数据安全且稳定,效率高,被普遍使用。下面是简单的案例

      1.创建Spring Boot项目,导入下列相关的依赖,还有web模块的依赖

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>4.3.1</version>
</dependency> <!-- springboot - Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--spring session 与redis应用基本环境配置,需要开启redis后才可以使用,不然启动Spring boot会报错 -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>

      2.在主配置类中开启RedisHttpSession

@EnableRedisHttpSession

      3.编写控制器

@Controller
public class MyController {
@RequestMapping("/set")
public String setSession (HttpServletRequest request){
String name = (String)request.getSession().getAttribute("name");
if(name !=null){//如果session存在了,直接跳转到成功页面,否则添加session并跳转到首页
return "success";
}
request.getSession().setAttribute("name","zhangsan");
return "index";
} @RequestMapping("/get")
public String getSession (HttpServletRequest request){
String name = (String)request.getSession().getAttribute("name");
System.out.println(name);
if(name != null){
return "success";
}else{
return "error";
}
}
}

    4.在application.properties中配置

server.port=8080
#远程连接redis的配置
spring.redis.host=192.168.2.130
spring.redis.port=6379
spring.redis.database=0
spring.redis.password=123456
spring.redis.timeout=5000
spring.redis.pool.max-idle=8
spring.redis.pool.min-idle=0
spring.redis.pool.max-active=8
spring.redis.max-wait=-1

    5.在template中写几个页面方便测试,这几个页面中每个页面放一句话就可以了,如下图

      

    6.运行Spring Boot项目,再修改配置文件中server.port=8081,运行Spring Boot项目(同时用两个不同端口的tomcat运行项目)

    7.测试:

      首先查看session是否存在,如下图所示,发现session都是null,跳转到错误页面

        

         

      在8080中第一次set,发现session为null后跳转到index页面,如下图

        

      刷新后,因为session存在,所以跳转到了成功页面

        

      再在8081中get,发现也跳转到了成功页面,说明8081的tomcat获取到了session

        

      最后,我们可以在redis中查看,发现多了一个session 数据包,如下图

        

      说明Spring Session + redis成功解决集群中session共享的问题

      注意:在redis中删除这个数据包,发现8080和8081都get不到session了,说明session没有存放在JVM中了,而是转存放在redis中了。

集群中Session共享解决方案分析的更多相关文章

  1. Java集群之session共享解决方案

    随着互联网的日益壮大,网站的pv和uv成线性或者指数倍的增加.单服务器单数据库早已经不能满足实际需求.比如像盛大,淘宝这样的大型网络公司,更是如此.     集群,也就是让一组计算机服务器协同工作,达 ...

  2. 关于 tomcat 集群中 session 共享的三种方法

    前两种均需要使用 memcached 或redis 存储 session ,最后一种使用 terracotta 服务器共享. 建议使用 redis,不仅仅因为它可以将缓存的内容持久化,还因为它支持的单 ...

  3. Asp.Net集群中Session共享

    今天遇到了这个问题,于是研究了一下.要解决这个问题,首先就要明白一些Session的机理.Session在服务器是以散列表形式存在的,我们都知道Session是会话级的,每个用户访问都会生成一个Ses ...

  4. spring session实现集群中session共享

    本文转自:http://dorole.com/1422/ 使用框架的会话管理工具,也就是本文要说的spring-session,可以理解是替换了Servlet那一套会话管理,既不依赖容器,又不需要改动 ...

  5. PHP 分布式集群中session共享问题以及session有效期的设置

    https://blog.csdn.net/m_nanle_xiaobudiu/article/details/81177698

  6. Session机制详解及分布式中Session共享解决方案

    一.为什么要产生Session http协议本身是无状态的,客户端只需要向服务器请求下载内容,客户端和服务器都不记录彼此的历史信息,每一次请求都是独立的. 为什么是无状态的呢?因为浏览器与服务器是使用 ...

  7. 通过memcached来实现对tomcat集群中Session的共享策略

    近期在做一套集群的实现,实现的方案是在Linux下完成对Apache + Tomcat 负载均衡的功能. 上述功能已经实现,有需要了解的朋友可以看我另外一篇博文. Linux下Apache与Tomca ...

  8. Redis+Tomcat+Nginx集群实现Session共享,Tomcat Session共享

    Redis+Tomcat+Nginx集群实现Session共享,Tomcat Session共享 ============================= 蕃薯耀 2017年11月27日 http: ...

  9. 集群间Session共享问题解决方案

    两个基本概念的生命周期 session: 当新客户端发现一个HTTP请求时服务端会创建一个session.并分配一个sessionID作为服务端来客户端的识别,session对象会保存在服务端.此时s ...

随机推荐

  1. LeetCode 116/117. 填充同一层的兄弟节点(Populating Next Right Pointers in Each Node)

    题目描述 给定一个二叉树 struct TreeLinkNode { TreeLinkNode *left; TreeLinkNode *right; TreeLinkNode *next; } 填充 ...

  2. 清明 DAY 3

    ans=1000*4 分别固定千位,百位,十位,个位为1,其余位置随便排 对于每一个质因数的n次方,共有n+1中选择方法,即这个质因数的0~n次方 故共有   4*3*5=60  种方法 (1)取两册 ...

  3. Python_序列对象内置方法详解_String

    目录 目录 前言 软件环境 序列类型 序列的操作方法 索引调用 切片运算符 扩展切片运算符 序列元素的反转 连接操作符 重复运算符 成员关系符 序列内置方法 len 获取序列对象的长度 zip 混合两 ...

  4. 【Java基础】JAVA 使用线程的几种方式

    之前放在自己网站上的例子,因为网站关闭,已经找不到了,想用的时候,没有的话又重新翻书是很麻烦的事情.所以重新记录一下,以备将来查看. 第一种,让任务类继承Runable接口,然后将任务类对象放入Thr ...

  5. Cocos2d-X多线程(3) cocos2dx中的线程安全

    在使用多线程时,总会遇到线程安全的问题.cocos2dx 3.0系列中新加入了一个专门处理线程安全的函数performFunctionInCocosThread(),他是Scheduler类的一个成员 ...

  6. 1 Java基础知识

    1)面向对象的特性有哪些? 答:封装.继承和多态. 2)Java 中覆盖(Override)和重载(Overload)是什么意思? 答:覆盖是指子类对父类方法的一种重写,只能比父类抛出更少的异常,访问 ...

  7. 【神经网络与深度学习】深度学习实战——caffe windows 下训练自己的网络模型

    1.相关准备 1.1 手写数字数据集 这篇博客上有.jpg格式的图片下载,附带标签信息,有需要的自行下载,博客附带百度云盘下载地址(手写数字.jpg 格式):http://blog.csdn.net/ ...

  8. adb将Apk内置到系统中(system/priv-app)

    https://blog.csdn.net/starhosea/article/details/78697007 so文件的处理是目前遇到过的问题.文章中解释了. 正文: 有时候我们在Android ...

  9. Akka系列(八):Akka persistence设计理念之CQRS

    前言........ 这一篇文章主要是讲解Akka persistence的核心设计理念,也是CQRS(Command Query Responsibility Segregation)架构设计的典型 ...

  10. 学习Linux第一周记

    2019/11/25 服务器硬件详述1) CPU                         作用:运算/控制      关注信息 :路数 服务器中CPU的颗数   一般有  (单路    双路  ...