📌 前言:从“以为做好了”到“被现实打脸”

相信很痛同学在做高并发项目之前,一直以为登录功能是最简单的。

只要 request.getSession()一下,用户就能登录了,对吧?

直到我把项目部署到 Nginx 集群​ 之后。

测试的时候差点把我送走:明明刚登录成功,刷新一下页面,又被踢回登录页了。

这就是我踩的第一个分布式大坑:Session 共享问题

🚨 问题现象(集群下的灵异事件)

单机模式下,一切岁月静好:

浏览器 → 服务器 A
Session 存在 A 的内存里 ✅

但是上了集群模式(多台服务器)后:

Nginx
        /     \
    Server A   Server B

诡异的现象出现的原因:

  1. 用户第一次访问,请求被分配到 Server A,登录成功,Session 存在 A 里。

  2. 用户刷新页面,请求被分配到 Server B

  3. Server B 懵了 :我这儿没你的 Session 啊?

  4. 结果 :用户看到 “请重新登录”

  5. 总结 : “这就是 Session 拷贝在集群下的致命缺陷:Session 是本地内存的,节点之间不共享,用户一换机器,登录态就丢了。”

📌 你必须懂的:Session 底层逻辑

       很多同学只知道 request.getSession(),但不知道里面发生了什么。

1. Session 的创建流程
  1. 首次请求:服务端发现请求头里 没有 JSESSIONID

  2. 创建对象:Tomcat 在内存中创建一个新的 HttpSession对象。

  3. 返回 ID:服务端通过响应头 Set-Cookie: JSESSIONID=xxx,把 ID 写给浏览器。

2. Session 的生命周期(面试常问)

阶段

触发条件

备注

创建

第一次调用 getSession()

不一定是登录那一刻

存活

会话未中断

依赖 Cookie

销毁

超时(默认30min)

web.xml可配

销毁

主动 invalidate()

退出登录时

销毁

服务器宕机

非持久化下致命

3,Session 的工作原理(核心流程)

1️⃣ 第一次请求
  • 服务端发现请求中没有 SessionId

  • 创建一个新的 Session

  • 生成一个唯一的 SessionId

2️⃣ 服务器返回 SessionId
  • 通常通过 Cookie​ 返回给客户端

3️⃣ 后续请求
  • 浏览器自动携带 SessionId

  • 服务端根据 SessionId查找对应的 Session

四、Redis 改进方案

Session 的本质没有改变,只是存储介质换了地方。

改造前(出问题)
用户 → Server A(Session 在 A 内存)
用户 → Server B(没有 Session) ❌
改造后(解决问题)
用户 → Server A / Server B
                 ↓
              Redis
工作流程
  1. 用户第一次访问 Server A

    • 创建 Session

    • Session 数据写入 Redis

  2. 用户第二次访问 Server B

    • Server B 从 Redis 读取 Session

    • ✅ 登录状态仍然有效


五、关键优化点

1️⃣ 设置有效期
  • 防止 Redis 内存无限增长

  • 与 Session 超时时间保持一致

2️⃣ 双拦截器设计(重点)

拦截器

作用

第一层

判断用户是否登录

第二层

刷新 Redis 中 Token / Session 的有效期

✅ 解决“用户一直在操作,却被强制下线”的问题。


💡 一句话总结(面试必背)

Session 的本质没有改变,只是将其存储实现从服务器内存替换为 Redis,从而解决分布式环境下的 Session 共享问题。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐