分布式系统要做到用户友好,需要对用户的session进行存储,存储的方式有以下几种:

  1. 本地缓存

  2. 数据库

  3. 文件

  4. 缓存服务器

可以看一些不同方案的优缺点

1.本地机器或者本地缓存。优点:速度快  缺点:服务宕机后重启用户信息丢失,用户不优好

2.数据库。优点:技术栈简单  缺点:速度慢

3.文件。优点:技术栈简单,速度适中 缺点:无灾备或者灾备方案成本高

4.缓存服务器。一般是内存服务器,优点:速度快 可以和原有技术栈契合,有现成的解决方案。缺点:不明显

如果使用java语言,并且缓存服务器为redis,可以使用开源的spring session项目来解决。

spring session项目现有三个自项目,分别是

spring-session-data-redis  使用redis方式

spring-session-hazelcast   使用hazelcast方式

spring-session-jdbc  使用jdbc方式

在这里我建议大家使用redis方式,它提供了注解式和编程式不同的方法。具体如何使用,网上有很多实例,我就不赘述。我想和大家一起深入内部看一下,spring-session项目的github地址为:https://github.com/spring-projects/spring-session.git

我们只看spring-session-data-redis,实现非常简单。它总共只有12个类

核心类只有一个

RedisOperationsSessionRepository

这个类内部定义了session的实现

RedisSession
/**
* A custom implementation of {@link Session} that uses a {@link MapSession} as the
* basis for its mapping. It keeps track of any attributes that have changed. When
* {@link org.springframework.session.data.redis.RedisOperationsSessionRepository.RedisSession#saveDelta()}
* is invoked all the attributes that have been changed will be persisted.
*
* @author Rob Winch
* @since 1.0
*/
final class RedisSession implements Session {
private final MapSession cached;
private Instant originalLastAccessTime;
private Map<String, Object> delta = new HashMap<>();
private boolean isNew;
private String originalPrincipalName;
private String originalSessionId;
注意:
delta 是增量 cached是存量

我们来看这个RedisSession的创建 销毁及修改

RedisSession内部存储如下(示例)

* <pre>* HMSET spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe creationTime 1404360000000 maxInactiveInterval 1800 lastAccessedTime 1404360000000 sessionAttr:attrName someAttrValue sessionAttr2:attrName someAttrValue2
* EXPIRE spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe 2100
* APPEND spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe ""
* EXPIRE spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe 1800
* SADD spring:session:expirations:1439245080000 expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe
* EXPIRE spring:session:expirations1439245080000 2100
* </pre>

RedisSession的数据结构是Hash

* <p>* Each session is stored in Redis as a
* <a href="http://redis.io/topics/data-types#hashes">Hash</a>. Each session is set and
* updated using the <a href="http://redis.io/commands/hmset">HMSET command</a>. An
* example of how each session is stored can be seen below.
* </p>

RedisSession的失效

* <h3>Expiration</h3>*
* <p>* An expiration is associated to each session using the
* <a href="http://redis.io/commands/expire">EXPIRE command</a> based upon the
* {@link org.springframework.session.data.redis.RedisOperationsSessionRepository.RedisSession#getMaxInactiveInterval()}
* . For example:
* </p>

RedisSession的更新有一个比较重要的方法:

/**
* Saves any attributes that have been changed and updates the expiration of this
* session.
*/
private void saveDelta() {
String sessionId = getId();
saveChangeSessionId(sessionId);
if (this.delta.isEmpty()) {
return;
}
getSessionBoundHashOperations(sessionId).putAll(this.delta);
String principalSessionKey = getSessionAttrNameKey(
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME);
String securityPrincipalSessionKey = getSessionAttrNameKey(
SPRING_SECURITY_CONTEXT);
if (this.delta.containsKey(principalSessionKey)
|| this.delta.containsKey(securityPrincipalSessionKey)) {
if (this.originalPrincipalName != null) {
String originalPrincipalRedisKey = getPrincipalKey(
this.originalPrincipalName);
RedisOperationsSessionRepository.this.sessionRedisOperations
.boundSetOps(originalPrincipalRedisKey).remove(sessionId);
}
String principal = PRINCIPAL_NAME_RESOLVER.resolvePrincipal(this);
this.originalPrincipalName = principal;
if (principal != null) {
String principalRedisKey = getPrincipalKey(principal);
RedisOperationsSessionRepository.this.sessionRedisOperations
.boundSetOps(principalRedisKey).add(sessionId);
}
} this.delta = new HashMap<>(this.delta.size()); Long originalExpiration = (this.originalLastAccessTime != null)
? this.originalLastAccessTime.plus(getMaxInactiveInterval())
.toEpochMilli()
: null;
RedisOperationsSessionRepository.this.expirationPolicy
.onExpirationUpdated(originalExpiration, this);
}

小结:

1.session是键值对形式的,对应redis的数据结构hash

2.session的存储形式使用redis非常方便

spring-session-data-redis解决session共享的问题的更多相关文章

  1. 170222、使用Spring Session和Redis解决分布式Session跨域共享问题

    使用Spring Session和Redis解决分布式Session跨域共享问题 原创 2017-02-27 徐刘根 Java后端技术 前言 对于分布式使用Nginx+Tomcat实现负载均衡,最常用 ...

  2. 使用Spring Session和Redis解决分布式Session跨域共享问题

    http://blog.csdn.net/xlgen157387/article/details/57406162 使用Spring Session和Redis解决分布式Session跨域共享问题

  3. spring boot集成redis实现session共享

    1.pom文件依赖 <!--spring boot 与redis应用基本环境配置 --> <dependency> <groupId>org.springframe ...

  4. 基于redis解决session分布式一致性问题

    1.session是什么 当用户在前端发起请求时,服务器会为当前用户建立一个session,服务器将sessionId回写给客户端,只要用户浏览器不关闭,再次请求服务器时,将sessionId传给服务 ...

  5. Spring boot集成Redis实现sessions共享时,sessions过期时间问题分析

    Springboot鼓励零配置的方式,帮你做好大部分重复劳动的事,好到不能再好:具体的Redis安装方法和Springboot集成Redis方法,可以去搜索相关文章或参考该文章http://www.c ...

  6. Spring-session+Redis解决Session共享

    1. 保证Redis启动           2. 导入依赖                SpringBoot+Spring-Session+Redis <!--spring boot 与re ...

  7. nginx负载均衡中利用redis解决session一致性问题

    关于session一致性的现象及原因不是本小作文的重点,可以另行找杜丽娘O(∩_∩)O哈哈~重点是利用redis集中存储共享session的实际操作. 一.业务场景:nginx/tomcat/redi ...

  8. Spring mvc Data Redis—Pub/Sub(附Web项目源码)

    一.发布和订阅机制 当一个客户端通过 PUBLISH 命令向订阅者发送信息的时候,我们称这个客户端为发布者(publisher). 而当一个客户端使用 SUBSCRIBE 或者 PSUBSCRIBE ...

  9. spring boot + session+redis解决session共享问题

    自己没有亲自试过,不过看了下这个例子感觉靠谱,以后做了测试,在加以说明. PS:后期经验证,上面例子可行.我们平时存session里面的值,直接存在了redis里面了.

  10. 单点登录实现(spring session+redis完成session共享)

    一.前言 项目中用到的SSO,使用开源框架cas做的.简单的了解了一下cas,并学习了一下 单点登录的原理,有兴趣的同学也可以学习一下,写个demo玩一玩. 二.工程结构 我模拟了 sso的客户端和s ...

随机推荐

  1. gdb调试技巧 找到php执行进程当前执行的代码

    假设线上有一段php脚本,突然在某天出问题了,不处理但是进程没有退出.这种情况可能是异常休眠或者是有段死循环代码,但是我们怎么定位呢,我们这个时候最想知道的应该是这个脚本在此刻在做什么吧.这个是gdb ...

  2. 64位Redhat系统应用(c++代码)搭建-使用informix和g++编译

    这篇博客很有必要写下来,记录我在一个比较原生的Linux系统上搭建一套应用所遇到的各种问题和各种坑. 关于这套应用,算是我离职前的一个项目,不完成的话没有办法交差,同时,这个项目也比较紧,合作行一直在 ...

  3. springmvc mybatis shiro ios android构建cms系统

    开发语言: java.ios.android 部署平台: linux.window jdk版本:JDK1.7以上版本 开发工具: eclipse.idea等 服务器中间件:Tomcat 6.7.Jbo ...

  4. mvc输出json时报HTTP Status 406错误

    1.mvc输出json时报HTTP Status 406错误 错误纠结了2天时间,今天总与整对了,少jackson-databind引用 对于Spring 4.1.x 和以上, jackson-dat ...

  5. Python(五) 字典

  6. 算法竞赛新编??---WERTYU,UVa10082

    P47 例题:3-2  WERTYU,UVA10082 注:作者的想法是找出输入字符在常量数组中的位置(使用for( i = 1; s[i] && s[i] != c;i++);语句来 ...

  7. UVa 11728 Alternate Task (枚举)

    题意:给定一个 n,求一个最大正整数 N 使得 N 的所有正因数和等于 n. 析:对于任何数一个 n,它的所有正因子都是大于等于本身的,因为 n 本身就是自己的正因数,这样的就可以直接暴力了,答案肯定 ...

  8. Android中的EventBus

    1.分析 EventBus是一个针对Android的事件发布和订阅的框架,主要功能是替代Intent,Handler,BroadCast在Fragment,Activity,Service,线程之间传 ...

  9. API网关设计(一)之Token多平台身份认证方案(转载)

    原文:https://segmentfault.com/a/1190000018535570?utm_source=tag-newest 概述 今天咱们面对移动互联网的发展,系统一般是多个客户端对应一 ...

  10. Android ------------------ 带边框的圆角矩形

    <?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http:/ ...