Session共享问题

session就是服务器里的一个内存数据

image-20210315204249084

Session共享问题

分布式下session共享问题

  • 不同域名不能共享
  • 同一个服务,复制多份,session不同步问题
  • 不同服务,session不能共享

Session共享解决

session复制

image-20210315204918578

优点:

  • web-server(Tomcat)原生支持,只需要修改配置文件

缺点

  • session同步需要数据传输,占用大量网络带宽,降低服务器群的业务处理能力
  • 任意一台web-server保存的数据都是所有web-server的session总和,受到内存限制无法水平拓展更多server
  • 大型分布式集群情况下,由于所有的web-server都全量保存数据,所以不可取

客户端存储

image-20210315205223753

优点

  • 服务器不需要存储sessio,用户保存自己的session信息到cookie中.节省服务端资源

缺点

  • 都是缺点,基本不可能使用
  • 每次http请求,携带用户cookie中的完整信息,浪费网络带宽
  • session数据放在cookie中,cookie有长度限制4k,不能保存大量信息
  • session数据放在cookie中,存在泄漏,篡改,窃取等安全问题

hash一致性

image-20210315205635833

优点

  • 只需要改nginx配置,不需要修改应用代码
  • 负载均衡,只要hash属性的值分布是均匀的,多台web-server的负载是均衡的
  • 可以支持web-server水平拓展(session同步法是不行的,受内存限制)

缺点

  • session还是存在web-server中的,所以web-server重启可能导致session丢失, 影响业务
  • 如果web-server水平拓展,rehash后session重新分布,也会有一部分用户路由不到正确的session

但是以上两种缺点问题也不是很大,因为session本来都是有效期的,所以这两种反向代理的方式可以使用

统一存储

image-20210315205926564

优点:

  • 没有安全隐患
  • 可以水平拓展,数据库/缓存水平切分即可
  • web-server重启或者扩容都不会有session丢失

不足

  • 增加了一次网络调用,并且需要修改应用代码
  • 如将所有的getSession方法替换为从Redis查数据
  • 上面缺点 SpringSession可以完美解决

引入依赖

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/org.springframework.session/spring-session-data-redis -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
<version>2.3.0.RELEASE</version>
</dependency>

在配置文件

1
2
3
4
5
6
7
8
session:
store-type: redis

server:
port: 8200
servlet:
session:
timeout: 30m

主类上标注

1
@EnableRedisHttpSession //整合redis作为session存储

image-20200825003920688

解决子域作用共享问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Configuration
public class YtmallSessionConfig {

@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setCookieName("YTSESSION");
serializer.setDomainName(".ytmall.com");
return serializer;
}

//自定义序列化
@Bean
public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
return new GenericFastJsonRedisSerializer();
}

核心原理

@EnableRedisHttpSession导入RedisHttpSessionConfiguration

  1. 给容器中添加了一个组件

    sessionRepository (可以自定义实现)>>

    RedisOperationSessionRepository: redis操作session. session的增删改查封装类

  2. SessionRepositoryFilter: session存储过滤器 每一个请求过来都必须经过filter

    1. 创建的时候,就从容器中获取到了SessionRepository

    2. SessionRepositoryFilter: 把原生的请求做了包装, 包装原始请求对象

    3. 放行 放的是包装后的request和response 包装后的对象应用到了我们后面的整个执行链

      以后获取session,都调用request.getSession()

      wrappedRequest.getSession() 全是在sessionrepository中获取到的

      (装饰者模式)