【SSO单点登录】分布式Session存在问题&& spring-session的设计之妙

本文探讨了分布式环境下session存在的问题,如内存占用高和不同服务器间session无法共享。通过介绍nginx的ip_hash策略,展示了其解决部分问题的方式。接着深入解析了Spring Session的工作原理,包括查询过程、Redis中的数据结构以及如何处理session过期。文章还讨论了Redis的过期策略——惰性删除和周期删除,并揭示了Spring Session如何确保及时触发过期事件。最后提到了用token取代session的可能性,以简化服务端的登录状态维护。
摘要由CSDN通过智能技术生成

👉本篇速览

  • session存在的问题

    • 分布式session如何解决
      • nginx的ip_hash
  • spring-session

    • 查询的原理&源码
    • 过期的原理&源码
      • 扩展redis过期策略
      • 为何spring-session要如此设计数据结构
  • token取代session,实现服务端到客户端的跨变

🎯session存在的问题

  1. 服务端需要存储session,占用内存高
  2. 不同服务器,无法共享session【分布式的场景】,这种情况下通常需要借助redis等数据库来做存储

没有什么是加一层解决不了的hhh

分布式session如何解决

当我们用nginx做负载均衡时,用户在A服务器登录了,A服务器存储了session,客户端也存储了cookie,其中有JSESSIONID。

此时负载均衡,访问B服务器的话,B服务器是没有这个session的,客户端的cookie里边JSESSIONID也就找不到对应的session,相当于没有登录,此时如何解决呢?

nginx的ip_hash

用nginx的ip_hash可以使得某个ip的用户,只固定访问某个特定的服务器,这样就不会跑到其他服务器,也就不需要考虑session共享的问题了

但与此同时,这又违背了Nginx负载均衡的初衷,请求都固定打到某一台服务器,宕机就不好办了,于是我们有了spring-session

🎯spring session

查询的原理

当请求进来的时候,SessionRepositoryFilter 会先拦截到请求,将 request 和 response 对象转换成 SessionRepositoryRequestWrapper 和SessionRepositoryResponseWrapper 。后续当第一次调用 request 的getSession方法时,会调用到 SessionRepositoryRequestWrapper 的getSession方法。

这个方法是被重写过的,逻辑是先从 request 的属性中查找,如果找不到;再查找一个key值是"SESSION"的 Cookie,通过这个 Cookie 拿到 SessionId 去 Redis 中查找,如果查不到,就直接创建一个RedisSession 对象,同步到 Redis 中。

说的简单点就是:拦截请求,将之前在服务器内存中进行 Session 创建销毁的动作,改成在 Redis 中创建。

具体源码


    /**
     * HttpServletRequest getSession()实现
     */
    @Override
    public HttpSessionWrapper getSession() {
        return getSession(true);
    }

    @Override
    public HttpSessionWrapper getSession(boolean create) {
        HttpSessionWrapper currentSession = getCurrentSession();
        if (currentSession != null) {
            return currentSession;
        }
        //从当前请求获取sessionId
        String requestedSessionId = getRequestedSessionId();
        if (requestedSessionId != null
                && getAttribute(INVALID_SESSION_ID_ATTR) == null) {
            S session = getSession(requestedSessionId);
            if (session != null) {
                this.requestedSessionIdValid = true;
                currentSession = new HttpSessionWrapper(session, getServletContext());
                currentSession.setNew(false
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值