一、Session
1.1 概述
Session:在计算机中,尤其是在网络应用中,称为“会话控制”。它是一种记录客户状态的机制,客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。Session对象存储特定用户会话所需的属性及配置信息。- 当用户在应用程序的
Web页之间跳转时,存储在Session对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。
1.2 使用原理
二、分布式 Session
2.1 分布式 Session 问题
2.2 解决方案
2.2.1 方案一:session同步
-
优点:
web-server(Tomcat)提供原生支持,只需要修改配置文件。 -
缺点:
session需要同步数据传输,会占用大量网络带宽,降低了服务器群的业务处理能力。- 任意一台
web-server保存的数据都是所有web-server的session总和,会受到内存限制无法水平拓展更多的web-server。 - 大型分布式集群情况下,所有
web-server都全量保存数据,则该方案不可取。
-
示意图:
2.2.2 方案二:客户端存储
- 优点:服务器不需要存储
session,用户保存自己的session信息到cookie中,节省服务端资源。 - 缺点:
- 每次
http请求,携带用户在cookie中的完整信息,浪费网络带宽。 session数据存在cookie中,cookie有长度限制,并不能保存大量信息。- 存在泄露、篡改、窃取等安全隐患,则该方式不会使用。
- 每次
- 示意图:
2.2.3 方案三:hash一致性
- 优点:
- 只需要修改
nginx配置,不需要修改应用代码。 - 负载均衡:只要
hash属性的值分布是均匀的,多台web-server的负载也同样是均衡的。 - 可以支持
web-server水平拓展。
- 只需要修改
- 缺点:
session还是存在web-server中,所以web-server重启或者扩容后可能导致部分session丢失,影响到当前业务。- 若想进行水平拓展,
rehash后session会重新分布,则会有一部分用户路由不到正确的session。
- 说明:因为
session本来都是有时效的,所以以上缺点问题也不是很大。这两种反向代理方式都是可以使用的。 - 示意图:
2.2.4 方案四:后端统一存储
- 优点:
- 没有安全隐患。
- 可以水平拓展,在数据库/缓存维度进行切分即可。
web-server重启或者扩容都不会有session丢失。
- 缺点:
- 增加了一次网络调用。
- 需要修改应用代码,如:将
getSession()方法替换为从Redis查询数据的方式,由于该方式要去中间件服务获取数据,则要比通过读内存慢很多。
- 说明:以上缺点可以使用
SringSession完美解决。 - 示意图:
三、SpringSession
3.1 概述
Spring Session是Spring家族中的一个子项目, 它提供一组API和实现, 用于管理用户的session信息。- 它把
servlet容器实现的httpSession替换为spring-session, 专注于解决session管理问题,session信息存储在Redis中, 可简单快速且无缝的集成到我们的应用中。 - 它有以下特性:
- 提供用户
session管理的API和实现。 - 提供
HttpSession,以中立的方式取代web容器的session,比如tomcat中的session。 - 支持集群的
session处理,不必绑定到具体的web容器去解决集群下的session共享问题。
- 提供用户
3.2 整合
- 步骤一:依赖引入:
<!-- 整合 spring session 实现 session 共享-->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
- 步骤二:配置application.properties
# 指定存储类型
spring.session.store-type=redis
- 步骤三:主启动类增加注解
@EnableRedisHttpSession - 步骤四:增加配置类
@Configuration
public class SessionConfig {
@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
// 放大作用域
cookieSerializer.setDomainName("父级域名");
cookieSerializer.setCookieName("自定义cookie名");
return cookieSerializer;
}
@Bean
public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
return new GenericJackson2JsonRedisSerializer();
}
}
3.3 核心原理
-
@EnableRedisHttpSession导入RedisHttpSessionConfiguration配置- 给容器中添加了一个组件
RedisOperationsSessionRepository:Redis操作session的增删改查封装类; - 继承
SpringHttpSessionConfiguration初始化了一个SessionRepositoryFilter(session存储过滤器);每个请求过来都必须经过Filter组件;创建的时候,自动从容器中获取到了SessionRepository。
- 给容器中添加了一个组件
-
SessionRepositoryFilter- 将原生的
HttpServletRequest / Response包装成SessionRepositoryRequestWrapper / ResponseWrapper;包装后的对象应用到了后面整个执行链; - 以后获取
request.getSession(); 都会调用wrappedRequesr.getSession(); 从SessionRepository获取。
- 将原生的
-
说明:设计模式采用到了装饰者模式。
-
核心方法:
3.4 官方文档
其他具体使用细节,参考官方文档:docs.spring.io/spring-sess…
四、结束语
“-------怕什么真理无穷,进一寸有一寸的欢喜。”
微信公众号搜索:饺子泡牛奶。