在单体应用中,HttpSession 由应用服务器保存,天然可用。但系统拆分为多实例部署(负载均衡)或微服务后,用户的请求会落到不同实例,基于内存的 HttpSession 无法共享,登录态就会丢失。本文系统讲解分布式会话的常见解决方案及取舍。
单体应用只有一个进程,HttpSession 存在进程内存中,同一用户请求必然到达同一进程。但在分布式/微服务下:
用户请求 -> 负载均衡 -> 可能分发到 服务A / 服务B / 服务C如果 Session 只存在服务 A 内存,请求被分发到服务 B 时,就找不到 Session,用户被要求重新登录。
让集群内各实例互相复制 Session(如 Tomcat 的 DeltaManager)。各实例内存中都有全量 Session。
优点:实现简单,应用无感知。 缺点:Session 复制有网络开销与延迟,实例越多开销越大;存在内存冗余。仅适合小型集群,不适合大规模。
通过负载均衡器(Nginx 的 ip_hash、基于 Cookie 的 sticky)将同一用户的请求始终分发到同一实例。
Nginx: upstream xxx { ip_hash; server A; server B; }优点:实现简单,无需改动应用。 缺点:一旦该实例宕机,该实例上的所有用户 Session 全部丢失;扩容/缩容会导致 session 重新分布(用户被登出)。可用性差,不推荐作为主方案。
把 Session 存到 Redis,所有实例共享同一份 Session 数据。应用通过 Spring Session 等框架透明地切换到 Redis 存储。
优点:
实现(Spring Session + Redis):
# 引入 spring-session-data-redis 后,默认将 HttpSession 存到 Redis
spring:
session:
store-type: redis
timeout: 30m注意:Session 数据要序列化(JSON/Java 序列化),并避免把大对象放进 Session(Redis 内存成本高)。
不使用服务端 Session,而是把登录态信息放进客户端持有的 Token(最常用 JWT),服务端通过验签即可识别用户,无需存储任何会话状态。
JWT 结构(三部分,用 . 连接):
Header.Payload.Signatureexp。认证流程:
1. 用户登录 -> 服务端签发 JWT(含用户ID、过期时间)返回客户端
2. 客户端后续请求携带 JWT(Authorization: Bearer <token>)
3. 服务端验证签名和过期时间 -> 从 Payload 解析用户身份优点:
缺点与注意:
适用场景:适合接口鉴权、移动端、前后端分离;若需要"主动踢人""服务端可控会话",可结合 Redis 存储 JWT 或改用 Redis Session。
当系统有多个独立应用(如门户、后台、商城),用户登录一个应用后,希望访问其他应用无需重复登录。SSO 通过**认证中心(SSO Server)**统一管理登录态。
常见实现:
CAS 流程(简化):
1. 用户访问 应用A,未登录 -> 重定向到 认证中心
2. 认证中心校验登录(用户名/密码),生成 TGT 票据保存在认证中心,设置全局登录 Cookie
3. 认证中心生成 ST 服务票据,重定向回 应用A
4. 应用A 用 ST 向认证中心校验,换取用户信息,建立本地会话
5. 用户访问 应用B,同样重定向认证中心,认证中心发现已全局登录,直接签发 ST -> 免登录优点:一处登录,处处可用,用户体验好;集中管理认证与安全。 缺点:认证中心是单点,需高可用部署;协议实现较复杂。
| 方案 | 无状态 | 可扩展 | 高可用 | 复杂度 | 适用场景 |
|---|---|---|---|---|---|
| Session 复制 | × | 差 | 中 | 低 | 小型集群 |
| 粘性会话 | × | 差 | 低 | 低 | 简单过渡方案 |
| Redis Session | √ | 好 | 好 | 中 | 主流的 Web 应用分布式会话 |
| JWT | √√ | 最好 | 好 | 中 | 前后端分离、移动端、微服务鉴权 |
| SSO(CAS/OAuth2) | 视实现 | 好 | 需高可用 | 高 | 多应用统一登录 |
选型建议:
HttpOnly、SameSite,防止被脚本读取和跨站请求伪造。| 维度 | 说明 |
|---|---|
| 技术原理 | 分布式一致性/事务/锁/ID 生成等原理与具体版本无关,长期有效 |
| 落地选型 | 新项目建议优先使用 Nacos/Redis/Seata 等成熟组件(JDK 17+ 兼容) |
| Java 版本 | 示例代码基于 JDK 8 编写,JDK 17/21 下语法兼容 |
本文讲解的分布式系统核心问题与解决方案原理稳定,不随框架版本变化;落地时选用支持 JDK 17/21 的组件版本即可。