章节目录:
一、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 官方文档
其他具体使用细节,参考官方文档:https://docs.spring.io/spring-session/docs/2.5.0/reference/html5/#samples
四、结束语
“-------怕什么真理无穷,进一寸有一寸的欢喜。”
微信公众号搜索:饺子泡牛奶。