一、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. SpringMvc的自动装箱和GET请求参数可以为自定义对象的思考

    在我的概念里边,GET请求需要加上注解@RequestParam,然后它的参数类型只能是 基本数据类型 或者 基本数据类型的包装类,比如:@RequestParam String name(默认是必传 ...

  2. hdu5238 calculator (线段树+crt)

    (并不能)发现29393不是质数,而是等于7*13*17*19 于是可以用四个线段树分别维护模意义下,对x进行一个区间的操作后的值 最后再把这四个的答案用crt拼起来 也可以不crt,而是预处理0~2 ...

  3. 监控MySQL|Redis|MongoDB的执行语句(go-sniffer)

    上节回顾:https://www.cnblogs.com/dotnetcrazy/p/9986873.html 以CentOS为例: 1.环境 PS:如果不需要Golang环境,可以编译后把执行文件c ...

  4. 映像文件工具srec

    目录 映像文件工具srec 介绍与帮助 常用例子 常用选项 一个实际的例子 hex转bin 数据填充 文件合并 文件分割 加入CRC 查看信息 使用命令集合的文本 详细文件格式的描述 附录:MDK的例 ...

  5. mycat 使用

    介绍 支持SQL92标准 支持MySQL.Oracle.DB2.SQL Server.PostgreSQL等DB的常见SQL语法 遵守Mysql原生协议,跨语言,跨平台,跨数据库的通用中间件代理. 基 ...

  6. Hadoop生态圈-zookeeper完全分布式部署

    Hadoop生态圈-zookeeper完全分布式部署 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 本篇博客部署是建立在Hadoop高可用基础之上的,关于Hadoop高可用部署请参 ...

  7. 分布式监控系统开发【day38】:报警策略设计(二)

    一.策略和动作多对多的好处坏处 1.好处: 相同服务,相同策略的服务可以不用重复写好多次触发器 2.坏处: 1.策略A给小李和小罗发邮件2.策略B给小胡和小崔发邮件3.策略A是第三部发邮件4.策略B是 ...

  8. Docker:dockerfile自动构建镜像 [六]

    一.手动docker镜像的缺点 相对于手动制作的docker镜像,使用dockerfile构建的镜像有以下优点: 1.dockerfile只有几kb,便于传输 2.使用dockerfile构建出来的镜 ...

  9. 浅谈PageHelper插件分页实现原理及大数据量下SQL查询效率问题解决

    前因:项目一直使用的是PageHelper实现分页功能,项目前期数据量较少一直没有什么问题.随着业务扩增,数据库扩增PageHelper出现了明显的性能问题.几十万甚至上百万的单表数据查询性能缓慢,需 ...

  10. [再寄小读者之数学篇](2014-06-23 Hardy 空间、BMO空间与 Triebel-Lizorkin 空间)

    $$\bex 0<p<\infty\ra H_p=\dot F^0_{p,2};\quad BMO=\dot F^0_{\infty,2}. \eex$$ see [H. Triebel, ...