一、Cookie机制和Session机制回顾
1)定义:Session成为“会话”,具体是指一个终端用户与交互系统进行通信的时间间隔,通常指从注册进入系统到注销退出系统之间所经过的时间。Session实际上是一个特定的时间概念。
 
2)HTTP协议与状态保持:HTTP 协议本身是无状态的,这与HTTP协议本来的目的是相符的,客户端只需要简单的向服务器请求下载某些文件,无论是客户端还是服务器都没有必要纪录彼此过去的行为,每一次请求之间都是独立的,好比一个顾客和一个自动售货机或者一个普通的(非会员制)大卖场之间的关系一样。
 
cookie的作用就是为了解决HTTP协议无状态的缺陷。至于后来出现的session机制则是又一种在客户端与服务器之间保持状态的解决方案。
 
3)Cookie和Session机制的区别和联系(几个有趣的例子):
1、该店的店员很厉害,能记住每位顾客的消费数量,只要顾客一走进咖啡店,店员就知道该怎么对待了。这种做法就是协议本身支持状态。
 
2、发给顾客一张卡片,上面记录着消费的数量,一般还有个有效期限。每次消费时,如果顾客出示这张卡片,则此次消费就会与以前或以后的消费相联系起来。这种做法就是在客户端保持状态。(Cookie原理)
 
3、发给顾客一张会员卡,除了卡号之外什么信息也不纪录,每次消费时,如果顾客出示该卡片,则店员在店里的纪录本上找到这个卡号对应的纪录添加一些消费信息。这种做法就是在服务器端保持状态。(Session原理)
 
由于HTTP协议是无状态的,cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案。同时我们也看到,由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助于cookie机制来达到保存标识的目的,但实际上它还有其他选择。
 
二、集群下实现Session共享的几种方案
 
1.请求精确定位:基于IP地址的Hash策略,将同一用户的请求都集中在一台服务器上,这台服务器上保存了该用户的Session信息。缺点:单点部署发生宕机时,Session丢失。
 
2.Session复制共享:比如可以用Tomcat自带的插件进行Session同步,使得多台应用服务器之间自动同步Session,保持一致。如果一台发生故障,负载均衡会遍历寻找可用节点,Session也不会丢失。缺点:必须是Tomcat和Tomcat之间,Session的复制也会消耗系统 的性能,使得同步给成员时容易造成内网流量瓶颈。
 
3.基于cache DB缓存的Session共享(推荐,Spring-Session也是同样的原理,同自定义的JRedis一起配置可以实现目的):使用Redis存取Session信息,应用服务器发生故障时,当Session不在内存中时就会去CacheDB中查找(要求Redis支持持久化),找到则复制到本机,实现Session共享和高可用。
 
分布式Session配置原理图
 

 
其他方式:利用公共的NFS服务器做共享服务器、完全利用Cookie(将Session数据全放在Cookie中)等。
 
三、基于Redis的Session共享实现(核心代码)
 
1)原理:写一个Session过滤器拦截每一次请求,在这里检查由Cookie生成的SessionID,进行创建或获取。核心是实现使用装饰类,实现Session在Redis中的存取操作。
2)此处存取方式为 sessionID+sessionKey作为Redis的key  ==== sessionValue作为Redis的value,这样保存了每次存取都从Redis中操作,效率更高。
3)注意:序列化方式推荐使用Apache下Commons组件——SerializationUtils 或 org.springframework.util.SerializationUtils

 1 //定义请求经过的Session过滤器
public class SessionFilter extends OncePerRequestFilter implements Filter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// 从cookie中获取sessionId,如果此次请求没有sessionId,重写为这次请求设置一个sessionId
String sid = CookieUtil.getCookieValue(request, GlobalConstant.JSESSIONID);
if (StringUtils.isEmpty(sid) || sid.length() != 36) {
sid = UUID.randomUUID().toString();
CookieUtil.setCookie(request, response, GlobalConstant.JSESSIONID, sid, 60 * 60);
}
// 交给自定义的HttpServletRequestWrapper处理
filterChain.doFilter(new HttpServletRequestWrapper(sid, request, response), response);
}
}
     //Cookie
public static void setCookie(HttpServletRequest request,
HttpServletResponse response, String name, String value, int seconds) {
if (StringUtils.isEmpty(name) || StringUtils.isEmpty(value))
return;
Cookie cookie = new Cookie(name, value);
//cookie.setDomain(domain);
cookie.setMaxAge(seconds);
cookie.setPath("/");
response.setHeader("P3P",
"CP='IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT'");
response.addCookie(cookie);
} public String getCookieValue(String name)
throws UnsupportedEncodingException {
Cookie cookies[] = request.getCookies();
if (cookies != null) {
for (int i = 0; i < cookies.length; i++) {
if (name.equalsIgnoreCase(cookies[i].getName())) {
return cookies[i].getValue();
}
}
}
return "";
}
     //SessionService实现   sidKey == sessionID+SessionKey
public Object getSession(String sidKey) {
Object realValue = null;
try {
String key = “SESSION_DISTRIBUTED_SESSIONID” + sidKey;
realValue = SerializeUtil.unserialize(RedisUtils.getInstance().get(key.getBytes()));
} catch (Exception e) {
LOG.error("Redis获取session异常" + e.getMessage(), e.getCause());
}
return realValue;
} public void saveSession(String sidKey, Object value) {
try {
String key = “SESSION_DISTRIBUTED_SESSIONID” + sidKey;
boolean isSetSuccess = RedisUtils.getInstance().set(key.getBytes(), SerializeUtil.serialize(value));
if (!isSetSuccess) {
LOG.error("Redis保存session异常");
}
} catch (Exception e) {
LOG.error("Redis保存session异常" + e.getMessage(), e.getCause());
}
} public void removeSession(String sidKey) {
try {
String key =“SESSION_DISTRIBUTED_SESSIONID”+ sidKey;
RedisUtils.getInstance().del(key.getBytes());
} catch (Exception e) {
LOG.error("Redis删除session的attribute异常" + e.getMessage(), e.getCause());
}
} public void removeAllSession(String sid) {
try {
String keyPattern =“SESSION_DISTRIBUTED_SESSIONID” + sid + "*";
Set<byte[]> keys = RedisUtils.getInstance().keys(keyPattern.getBytes());
for (byte[] key : keys) {
RedisUtils.getInstance().del(key);
}
} catch (Exception e) {
LOG.error("Redis删除session异常" + e.getMessage(), e.getCause());
}
} public Set<String> getAllKeys(String sid) {
try {
Set<String> keysResult = new HashSet<String>();
String keyPattern =“SESSION_DISTRIBUTED_SESSIONID” + sid + "*";
Set<byte[]> keys = RedisUtils.getInstance().keys(keyPattern.getBytes()); for (byte[] key : keys) {
keysResult.add(new String(key));
}
return keysResult;
} catch (Exception e) {
LOG.error("Redis删除session异常" + e.getMessage(), e.getCause());
return null;
}
}
 HttpServletRequestWrapper extends javax.servlet.http.HttpServletRequestWrapper
private HttpSession session; private HttpServletRequest request; private HttpServletResponse response; private String sid = ""; public HttpServletRequestWrapper(HttpServletRequest request) {
super(request);
} public HttpServletRequestWrapper(String sid, HttpServletRequest request) {
super(request);
this.sid = sid;
} public HttpServletRequestWrapper(String sid, HttpServletRequest request, HttpServletResponse response) {
super(request);
this.request = request;
this.response = response;
this.sid = sid;
if (this.session == null) {
this.session = new HttpSessionWrapper(sid, super.getSession(false), request, response);
}
} @Override
public HttpSession getSession(boolean create) {
if (this.session == null) {
if (create) {
this.session = new HttpSessionWrapper(this.sid, super.getSession(create), this.request, this.response);
return this.session;
} else {
return null;
}
}
return this.session;
} @Override
public HttpSession getSession() {
if (this.session == null) {
this.session = new HttpSessionWrapper(this.sid, super.getSession(), this.request, this.response);
}
return this.session;
}
     HttpSessionWrapper implements HttpSession{

     private String sid = "";

     private HttpSession session;

     private HttpServletRequest request;

     private HttpServletResponse response;

     private SessionService sessionService = (SessionService) SpringContextHolder.getBean("sessionService");

     public HttpSessionWrapper() {
} public HttpSessionWrapper(HttpSession session) {
this.session = session;
} public HttpSessionWrapper(String sid, HttpSession session) {
this(session);
this.sid = sid;
} public HttpSessionWrapper(String sid, HttpSession session,
HttpServletRequest request, HttpServletResponse response) {
this(sid, session);
this.request = request;
this.response = response;
} @Override
public Object getAttribute(String name) {
return sessionService.getSession(this.sid+"#"+name);
} @Override
public void setAttribute(String name, Object value) {
sessionService.saveSession(this.sid+"#"+name, value);
} @Override
public void invalidate() {
sessionService.removeAllSession(this.sid);
CookieUtil.removeCookieValue(this.request,this.response, GlobalConstant.JSESSIONID);
} @Override
public void removeAttribute(String name) {
sessionService.removeSession(this.sid+"#"+name);
} @Override
public Object getValue(String name) {
return this.session.getValue(name);
} @SuppressWarnings("unchecked")
@Override
public Enumeration getAttributeNames() {
return (new Enumerator(sessionService.getAllKeys(this.sid), true));
} @Override
public String getId() {
return this.sid;
}
69 }

集群环境下的Session共享的更多相关文章

  1. 集群环境下,Session管理的几种手段

    集群环境下,Session管理的几种手段 1.Session复制 缺点:集群服务器间需要大量的通信进行Session复制,占用服务器和网络的大量资源. 由于所有用户的Session信息在每台服务器上都 ...

  2. weblogic 12C集群环境下的session复制

    做过weblogic集群环境的人应该都清楚,要想实现session同步,必须满足两个条件:第一,在weblogic.xml里面增加session同步相关的代码:第二,所有放入session的类都要序列 ...

  3. 集群环境下的Session管理

    1. 集群环境下的管理HTTPSSession所遇到的问题 一台服务器对应这个一个session对象,无法在另外一个服务器互通 解决方法: 1. Session 的 Replication(复制)将当 ...

  4. nginx+php负载均衡集群环境中的session共享方案梳理

    在网站使用nginx+php做负载均衡情况下,同一个IP访问同一个页面会被分配到不同的服务器上,如果session不同步的话,就会出现很多问题,比如说最常见的登录状态. 下面罗列几种nginx负载均衡 ...

  5. 【原创】Tomcat集群环境下对session进行外部缓存的方法(2)

    Session对象的持久化比较麻烦,虽然有序列化,但是并不确定Session对象中保存的其他信息是否可以序列化,这可能是网上很多解决方案摒弃此种做法的原因,网上的很多做法都是将Session中的att ...

  6. 【原创】Tomcat集群环境下对session进行外部缓存的方法(1)

    BJJC网改版, 计划将应用部署在tomcat集群上,集群的部署方案为Apache+Tomcat6,连接件为mod_jk,其中开启了session复制和粘性session.计划节点数为3个. 到这,或 ...

  7. 集群环境下Shiro Session的管理

    问题引入 紧接上篇连接 在多台tomcat集群中,shiro管理的session需要放在Redis中,我们只需要增加redisSessionDAO的配置就行 <!-- 定义会话管理器的操作 表示 ...

  8. Shiro权限管理框架(二):Shiro结合Redis实现分布式环境下的Session共享

    首发地址:https://www.guitu18.com/post/2019/07/28/44.html 本篇是Shiro系列第二篇,使用Shiro基于Redis实现分布式环境下的Session共享. ...

  9. redis 与java的连接 和集群环境下Session管理

    redis 的安装与设置开机自启(https://www.cnblogs.com/zhulina-917/p/11746993.html)  第一步: a) 搭建环境 引入 jedis jar包 co ...

随机推荐

  1. 利用 Python_tkinter 完成 2048 游戏

    成品展示 具备基本的数据合并以及分数统计,不同数字的色块不同 产生随机数, 数据无法合并判定以及重新开始选项 同时可以判定游戏失败条件 需求分析 完成基本数据合并算法 游戏结束条件 界面展示 重置按钮 ...

  2. 从Java角度修复SQL注入漏洞

    很多情况因为过滤不严导致很多网站存在sql注入,这里以用户登陆为例,简单举例 首先创建一个测试的数据库 比较基础,不写创建过程了 java代码如下: package cn.basic.jdbc; im ...

  3. Day049--jQuery的文档操作和事件介绍

    今日内容 DOM操作(CRUD) js中DOM document.createElement('p') appendChild() insertBefore() removeChild() 创建元素 ...

  4. Fiddler--Composer

    Composer选项卡支持手动构建和发请求:也可以在Session列表中拖拽Session放到Composer中,把该Session的请求复制到用户界面: 点击"execute"按 ...

  5. Jenkins-在windows上安装及其部署

    Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能.其主要功能:1.持续的软件版本发布/测试项目. ...

  6. JN_0002:Win10禁止U盘拷贝文件的方法

    1,在电脑桌面使用快捷键win键+r唤出运行窗口,在搜索框中输入gpedit.msc,然后点击确定. 2,打开的本地组策略编辑器中依次点击展开计算机配置—管理模块—系统,在系统下找到并选中可移动存储访 ...

  7. Three ways to detect outliers

    Z-score import numpy as np def outliers_z_score(ys): threshold = 3 mean_y = np.mean(ys) stdev_y = np ...

  8. YYS FZU - 2278 (期望)JAVA

    题目链接: G - YYS FZU - 2278 题目大意: 我们现在想要收集到n个卡片,现在已知抽到每种卡片的概率为1/n,现在每隔(n-1)!天就可以进行一次抽奖,问收集齐所有卡片的期望天数. 具 ...

  9. Mac环境下的mongodb的安装

    1.安装MongoDB brew install mongodb 这个是默认安装最新版本的 mogodb,如果想安装指定版本可以先查看 mongodb 版本 brew search mongodb m ...

  10. Centos7.5 安装VirtualBox增强工具

    一.安装 1.自带tools:  选择VirtualBox工具栏 => 设备 => 安装增强功能 2.挂载光驱 3.进入光驱目录,执行(一定要用root权限执行) ①安装gcc yum i ...