Session共享问题

session原理

1、用户第一次访问服务器,进行登录;
2、服务器把用户信息保存到session中,由sessionManager管理着;可以简单理解sessionmap,为服务器的一片内存空间
3、浏览器保存一个jsessionid=123cookie,这个123,就相当于是一个key,通过这个key,可以从session获取到用户信息
4、用户以后访问会带上cookie:jsessionid=123
5、浏览器关闭,清除会话cookie
6、下次访问,没有jsessionid,再创建一个,进入步骤1
在这里插入图片描述

Session共享问题

集群环境下的session共享问题

比如:会员服务部署在多台服务器上,假设浏览器第一次登陆,请求落在了一号服务器,那么一号服务器session中存了用户信息,那么下一次请求进来,落在了二号服务器,但是二号服务器并没有这个session,因此又要用户登陆一次,在存一次session信息
在这里插入图片描述
同一服务,集群后,session不同步问题

分布式环境下的session共享问题

session都是有作用域的,不能跨域共享。因此,不能跨不同域名共享。
在这里插入图片描述

在这里插入图片描述

Session解决方案

方案一:session复制

在这里插入图片描述

  • 优点
    • web-server(Tomcat)原生支持,只需要修改配置 文件
  • 缺点
    • session同步需要数据传输,占用大量网络带宽,降低了服务器群的业务处理能力
    • 任意一台web-server保存的数据都是所有web- serversession总和,受到内存限制无法水平扩展更多的web-server
    • 大型分布式集群情况下,由于所有web-server都全 量保存数据,所以此方案不可取。
    • 假设有100tomcat,每个tomcat里面都存了1G的数据,那么每个tomcat都得存其他99tomcatsession数据,99G!
    • 小型系统,就3-5tomcat,使用这种还可以

方案二:客户端存储

在这里插入图片描述

  • 优点
    • 服务器不需存储session,用户保存自己的 session信息到cookie中。节省服务端资源
  • 缺点
    • 都是缺点,这只是一种思路。
    • 具体如下:
    • 每次http请求,携带用户在cookie中的完整信息, 浪费网络带宽
    • session数据放在cookie中,cookie有长度限制 4K,不能保存大量信息
    • session数据放在cookie中,存在泄漏、篡改、 窃取等安全隐患
  • 这种方式不会使用。

方案三:hash一致性

利用负载均衡机制,来源于同一个ip的请求,永远用同一个服务器处理或者也可以使用业务字段,比如:用户sid=456,永远使用服务器A处理
在这里插入图片描述

  • 优点

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

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

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

方案四:统一存储

在这里插入图片描述

  • 优点
    • 没有安全隐患
    • 可以水平扩展,数据库/缓存水平切分即可
    • web-server重启或者扩容都不会有 session丢失
  • 不足
    • 增加了一次网络调用,并且需要修改应用代码;如将所有的getSession方法替换为从Redis查数据的方式。redis获取数据比内存慢很多
    • 上面缺点可以用SpringSession完美解决

不同服务,子域session共享

通过方案三或方案四,都能很好的解决同域名下,session共享的问题。

jsessionid这个cookie默认是当前系统域名的。当我们分拆服务,不同域名部署的时候,我们可以使用 如下解决方案;
在这里插入图片描述
比如
子域:
auth.gulimall.com在这里插入图片描述
父域是访问不到子域的cookie
在这里插入图片描述
将子域放大:
在这里插入图片描述
父域能访问改cookie了,有了cookie,就能到统一存储session的数据库中获取session
在这里插入图片描述
不但父域能访问该cookie,别的子域也能访问
在这里插入图片描述
在这里插入图片描述

SpringSession

使用SpringSession解决session共享问题和子域共享问题。

SpringSession整合Springboot

https://docs.spring.io/spring-session/docs/2.2.3.RELEASE/reference/html5/guides/boot-redis.html

依赖:

<!--spring-session-->
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>

配置:

spring:
  redis:
    host: 192.168.59.131
    port: 6379
  ##spring session的保存类型
  session:
    store-type: redis
server:
  ##session的超时时间  30分钟
  servlet:
    session:
      timeout: 30m    

启动类:@EnableRedisHttpSession

测试:

 @GetMapping(value = "test/springsession")
 @ResponseBody
 public void test(HttpSession session){
     User user=new User("张三",15);
     session.setAttribute("loginUSer",user);
 }
@AllArgsConstructor
@Data
class User implements Serializable {
    private String userName;
    private int age;
}

访问接口,auth.gulimall.com/test/springsession
redis中发现了session
在这里插入图片描述
问题:
1.把登录的用户给信息session存到了redis中,现在是我想在另一个域名下获取到这个session
2.现在session中的数据序列化到redis里,缓存的value值,默认使用jdk序列化机制,将序列化后的数据存到redis,能不能序列化为Json格式的数据呢?

对于问题1
比如:我想在父域http://gulimall.com/中获取或者在其他子域中获取,怎么办了?

先在其他域的对应的微服务中,也整合进SpringSession再说!
比如在父域中整合

 <!--spring-session-->
 <dependency>
     <groupId>org.springframework.session</groupId>
     <artifactId>spring-session-data-redis</artifactId>
 </dependency>
spring:
  redis:
    host: 192.168.59.131
    port: 6379
  ##spring session的保存类型
  session:
    store-type: redis
    
@EnableRedisHttpSession    

前端:
在这里插入图片描述
在这里插入图片描述
可以看到父域中也能获取到session中存储的用户信息!
在这里插入图片描述

问题1和2的解决

@Configuration
public class SessionConfig {
    /**
     * 配置cookie
     * @return
     */
    @Bean
    public CookieSerializer cookieSerializer(){
        DefaultCookieSerializer defaultCookieSerializer = new DefaultCookieSerializer();
        //放大子域
        defaultCookieSerializer.setDomainName("gulimall.com");
        defaultCookieSerializer.setCookieName("GULISESSION");
        
        return defaultCookieSerializer;
    }
    /**
     * 修改SpringSession序列化化机制
     */
    @Bean
    public RedisSerializer<Object> springSessionDefaultRedisSerializer () {
        return new GenericJackson2JsonRedisSerializer();
    }
}

把这个配置类放到子域名和父域名,对应的微服务中,即可。

启动微服务测试:
登录成功后,自动跳转到首页,查看cookie,有我们自定义的cookie信息。
在这里插入图片描述
存在redis里的数据也序列化成了json格式。
在这里插入图片描述
这样就解决了session共享问题!

解决方法来源:
在这里插入图片描述
在这里插入图片描述

SpringSession原理

@EnableRedisHttpSession导入RedisHttpSessionConfiguration配置
	1、给容器中添加了一个组件
	 SessionRepository =》RedisOperationsSessionRepository=》Redis操作session,session的增删改查封装类
	 2、SessionRepositoryFilter =>Filter:Session存储过滤器,每个请求过来都必须经过Filter
	 		1、创建的时候,就自动从容器中获取SessionRepository 
	 		2、原始的request,response都被包装。SessionRepositoryRequestWrapper,SessionRepositoryResponseWrapper
	 		3、以后获取到session。request.getSession()
	 		4、wrappedRequest.getSession()==>SessionRepository中获取

装饰者模式;

springsesion实现了:
自动延期:只要浏览器不关,session会自动续期

  • session 的运行依赖 session id,而 session id 是存在 cookie中的,也就是说,如果浏览器禁用了 cookie ,同时 session 也会失效(但是可以通过其它方式实现,比如在 url 中传递session_id
  • tomcatsession id中用JSESSIONID来表示;

1.在整合SpringSession之前,登录后,用户信息存在session里,浏览器上会有一个cookienameJSESSIONIDvalue是对应的session id
2.再整合SpringSession之后,该cookie,名字变为SESSION;
3.在自定义配置了cookie后,cookie名字被手动改为了GULISESSION

    /**
     * 配置cookie
     * @return
     */
    @Bean
    public CookieSerializer cookieSerializer(){
        DefaultCookieSerializer defaultCookieSerializer = new DefaultCookieSerializer();
        //放大子域
        defaultCookieSerializer.setDomainName("gulimall.com");
        defaultCookieSerializer.setCookieName("GULISESSION");
        
        return defaultCookieSerializer;
    }

但是有一个问题,就是浏览器上看到的sessionId,始终是和redis里看到的不一样。
在这里插入图片描述
在这里插入图片描述

原因:https://blog.csdn.net/wzygis/article/details/103509840
解决:

    /**
     * 配置cookie
     * @return
     */
    @Bean
    public CookieSerializer cookieSerializer(){
        DefaultCookieSerializer defaultCookieSerializer = new DefaultCookieSerializer();
        //放大子域
        defaultCookieSerializer.setDomainName("gulimall.com");
        defaultCookieSerializer.setCookieName("GULISESSION");
        defaultCookieSerializer.setUseBase64Encoding(false);
        return defaultCookieSerializer;
    }

哎,终于解决了我的疑惑,舒服了。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值