跳到主要内容

分布式会话

问题

分布式系统中如何管理用户会话?Session 共享有哪些方案?JWT 和 Session 各有什么优缺点?

答案

为什么需要分布式会话

单机部署时,Session 存在服务器内存中。集群部署后,用户请求可能被负载均衡分发到不同节点,导致 Session 丢失。

解决方案

方案一:Session 粘性(Sticky Session)

负载均衡器将同一用户的请求始终路由到同一节点。

Nginx ip_hash
upstream backend {
ip_hash;
server 192.168.1.1:8080;
server 192.168.1.2:8080;
}
优点缺点
简单,不需要改代码节点宕机 Session 丢失
无额外组件负载不均匀

方案二:Session 集中存储(Redis)

所有节点共享一个 Redis 存储 Session,最主流的方案。

Spring Session + Redis
// 添加依赖 spring-session-data-redis
// application.yml
// spring:
// session:
// store-type: redis
// timeout: 30m
// redis:
// host: localhost
// port: 6379

Spring Session 自动将 Session 存到 Redis,对业务完全透明。

优点缺点
Session 共享,任意节点可访问依赖 Redis,增加延迟
节点宕机不影响会话Redis 不可用则全部失效

方案三:JWT 无状态方案

服务端不存储 Session,将用户信息编码在 JWT Token 中,客户端每次请求携带 Token。

JWT 工具类
public class JwtUtil {
private static final String SECRET = "your-256-bit-secret";

public static String generateToken(Long userId, String role) {
return Jwts.builder()
.setSubject(userId.toString())
.claim("role", role)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 3600000))
.signWith(SignatureAlgorithm.HS256, SECRET)
.compact();
}

public static Claims parseToken(String token) {
return Jwts.parser()
.setSigningKey(SECRET)
.parseClaimsJws(token)
.getBody();
}
}

方案对比

维度Session + RedisJWT
状态有状态(服务端存储)无状态(客户端存储)
扩展性需要共享存储天然支持分布式
安全性较高(服务端控制)中等(无法主动失效)
踢人/注销直接删除 Session需要黑名单机制
存储Redis 内存占用Token 体积大,带宽开销
适用传统 Web 应用微服务、API、移动端
JWT 的主要问题
  1. 无法主动失效:Token 签发后,在过期前无法让它失效(退出登录需要黑名单)
  2. Token 续期:需要额外的 Refresh Token 机制
  3. 体积大:携带用户信息的 JWT 可能有几百字节
  4. 敏感信息泄露:Payload 是 Base64 编码(非加密),不要存敏感数据

常见面试问题

Q1: JWT 和 Session 怎么选?

答案

  • 传统 Web 应用(SSR):Session + Redis,能主动管理用户状态(踢人、强制下线)
  • 微服务 / API / 移动端:JWT,无状态、跨服务方便
  • 混合方案:JWT 做认证 + Redis 做会话状态管理(如在线状态)

大多数项目选 JWT + Refresh Token + Redis 黑名单。

Q2: JWT 如何实现登出?

答案

JWT 本身无法撤销,常见方案:

  1. Redis 黑名单:登出时将 Token(或 jti)加入 Redis 黑名单,设置 TTL 为 Token 剩余有效期
  2. 短过期 + Refresh Token:Access Token 15 分钟过期,登出时在 Redis 中删除 Refresh Token
  3. 版本号:用户信息中维护 token_version,登出时 +1,验证时对比版本号

Q3: 分布式环境下如何实现单点登录(SSO)?

答案

SSO 让用户在一个系统登录后,访问其他系统无需再次登录:

  1. CAS 模式:独立的认证中心,通过 Ticket 实现跨系统认证
  2. OAuth 2.0 / OIDC:通过授权码流程获取 Token
  3. 共享 Token:同一域名下共享 Cookie + Redis Session;跨域用 Token 方案

前端系列中有更详细的讨论,参见前端模块 JWT 认证设计单点登录系统

相关链接