详细说说分布式Session的几种实现方式


1. 基于客户端存储(Cookie-Based)

原理 :将会话数据直接存储在客户端 Cookie 中
实现

java 复制代码
// Spring Boot 示例
@Bean
public CookieSerializer cookieSerializer() {
    DefaultCookieSerializer serializer = new DefaultCookieSerializer();
    serializer.setCookieName("SESSION");
    serializer.setUseBase64Encoding(true); // Base64编码
    serializer.setUseHttpOnlyCookie(true); // 防XSS
    serializer.setCookiePath("/");
    serializer.setCookieMaxAge(1800); // 30分钟过期
    return serializer;
}

优点

  • 服务端完全无状态
  • 天然支持水平扩展
  • 实现简单

缺点

  • 单Cookie大小限制(4KB)
  • 每次请求需传输完整会话数据
  • 安全风险(需加密+签名)
  • 无法存储敏感数据

适用场景:会话数据量小(<1KB)的安全非敏感场景


2. Session 复制(Session Replication)

原理 :集群节点间同步 Session 数据
实现

xml 复制代码
<!-- Tomcat server.xml 配置 -->
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster">
  <Channel className="org.apache.catalina.tribes.group.GroupChannel">
    <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"/>
    <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
      <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
    </Sender>
  </Channel>
</Cluster>

同步方式

  • 全量复制:节点变更时广播所有 Session
  • 增量复制:仅同步修改的 Session(如 Tomcat DeltaManager)

优点

  • 任意节点可处理请求
  • 无单点故障

缺点

  • 网络带宽消耗大(N²问题)
  • 内存占用高(每节点存全量)
  • 集群规模受限(通常≤8节点)

适用场景:小型集群(≤5节点)且对性能要求不高


3. 集中式存储(Centralized Storage)

原理:会话数据集中存储在外部存储中

3.1 数据库存储
java 复制代码
// Spring Session JDBC 配置
@EnableJdbcHttpSession
public class SessionConfig {
    @Bean
    public JdbcIndexedSessionRepository sessionRepository(DataSource dataSource) {
        return new JdbcIndexedSessionRepository(dataSource);
    }
}

表结构

sql 复制代码
CREATE TABLE SPRING_SESSION (
    PRIMARY_ID CHAR(36) PRIMARY KEY,
    SESSION_ID CHAR(36) NOT NULL,
    CREATION_TIME BIGINT NOT NULL,
    LAST_ACCESS_TIME BIGINT NOT NULL,
    MAX_INACTIVE_INTERVAL INT NOT NULL,
    EXPIRY_TIME BIGINT NOT NULL
);
3.2 Redis存储(最常用
java 复制代码
// Spring Session Redis
@EnableRedisHttpSession
public class SessionConfig {
    @Bean
    public LettuceConnectionFactory connectionFactory() {
        return new LettuceConnectionFactory("redis-cluster", 6379);
    }
}

Redis数据结构

复制代码
Key: spring:session:sessions:<sessionId>
Type: Hash
Fields:
  creationTime: 1625000000000
  maxInactiveInterval: 1800
  lastAccessedTime: 1625001000000
  sessionAttr::user: {"id":1001,"name":"John"}

优点

  • 支持大规模集群
  • 内存读写性能高(Redis 10万+ QPS)
  • 数据持久化可选
  • 自动过期清理

缺点

  • 引入外部依赖
  • 网络延迟增加(约1-3ms)
  • 需处理缓存穿透/雪崩问题

优化技巧

java 复制代码
// 本地二级缓存(Caffeine)
@Bean
public SessionRepositoryCustomizer<RedisIndexedSessionRepository> customize() {
    return repo -> repo.setDefaultMaxInactiveInterval(1800);
}

4. 粘性会话(Sticky Session)

原理 :负载均衡器将同一用户的请求固定路由到同一节点
Nginx配置

nginx 复制代码
upstream backend {
    ip_hash; # 基于IP的粘性会话
    server 192.168.1.101:8080;
    server 192.168.1.102:8080;
}

优点

  • 实现简单
  • 无跨节点同步开销
  • 兼容传统应用

缺点

  • 节点故障导致会话丢失
  • 负载不均(热点用户)
  • 扩容时需迁移会话

适用场景:对会话一致性要求不高的传统应用


5. Token-Based 会话(JWT)

原理 :无状态会话,信息包含在Token中
实现

java 复制代码
// JWT 生成
String jwt = Jwts.builder()
    .setSubject("user123")
    .claim("roles", "admin,user")
    .setExpiration(new Date(System.currentTimeMillis() + 3600000))
    .signWith(SignatureAlgorithm.HS256, "secretKey")
    .compact();

Token结构

复制代码
Header: {"alg":"HS256","typ":"JWT"}
Payload: {"sub":"user123","roles":["admin","user"],"exp":1625005000}
Signature: HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

优点

  • 完全无状态
  • 天然支持跨域
  • 减少数据库查询

缺点

  • Token无法主动失效
  • 数据量受限(URL长度限制)
  • 安全风险(Token泄露)

解决方案

  • 短有效期 + Refresh Token
  • 使用黑名单(Redis记录失效Token)

方案选型对比

方案 扩展性 性能 可靠性 安全性 实现复杂度
客户端存储 ★★★★★ ★★★★☆ ★★☆☆☆ ★☆☆☆☆ ★★☆☆☆
Session复制 ★★☆☆☆ ★★☆☆☆ ★★★★☆ ★★★★☆ ★★★☆☆
Redis集中存储 ★★★★★ ★★★★☆ ★★★★☆ ★★★★☆ ★★★☆☆
数据库存储 ★★★★☆ ★★☆☆☆ ★★★★★ ★★★★☆ ★★★☆☆
粘性会话 ★★☆☆☆ ★★★★☆ ★★☆☆☆ ★★★☆☆ ★☆☆☆☆
JWT ★★★★★ ★★★★★ ★★★☆☆ ★★★☆☆ ★★★★☆

最佳实践建议

  1. 首选方案

    graph LR A[会话数据量] -->|<1KB| B(JWT) A -->|1-10KB| C(Redis集群) A -->|>10KB| D(数据库+本地缓存)
  2. 安全加固

    • Redis启用TLS通信
    • 设置HttpOnlySecure的Cookie
    • 定期轮换加密密钥
    java 复制代码
    // Cookie安全设置
    DefaultCookieSerializer serializer = new DefaultCookieSerializer();
    serializer.setUseSecureCookie(true); // 仅HTTPS传输
    serializer.setSameSite("Strict"); // 防CSRF
  3. 高可用设计

    • Redis Cluster + Sentinel
    • 多级缓存(Redis + 本地Caffeine)
    java 复制代码
    // 多级缓存配置
    @Bean
    public SessionRepository<?> sessionRepository() {
        MapSessionRepository memoryRepo = new MapSessionRepository();
        RedisIndexedSessionRepository redisRepo = ...;
        return new DelegatingSessionRepository(memoryRepo, redisRepo);
    }
  4. 性能优化

    • 启用spring.session.redis.flush-mode=immediate
    • 使用MessagePack序列化替代JSON
    yaml 复制代码
    spring:
      session:
        redis:
          flush-mode: immediate # 立即写入
          namespace: "app:sessions"
  5. 迁移方案

    生产 开发 传统单机Session 添加Spring Session依赖 选择存储后端 Redis集群 嵌入式H2 配置负载均衡器 灰度迁移流量


特殊场景处理

  1. 跨域会话

    • 使用OAuth 2.0/JWT
    • 设置SameSite=None + Secure
  2. 大Session处理

    java 复制代码
    // 分片存储
    public class LargeSessionStrategy {
        public void saveFragment(String sessionId, String fragmentKey, byte[] data) {
            redisTemplate.opsForHash().put(sessionId, fragmentKey, data);
        }
    }
  3. 实时踢人下线

    java 复制代码
    // 发布会话失效事件
    @Autowired
    private ApplicationEventPublisher eventPublisher;
    
    public void forceLogout(String sessionId) {
        eventPublisher.publishEvent(new SessionDestroyedEvent(sessionId));
        redisTemplate.delete("spring:session:sessions:" + sessionId);
    }

你想要的我全都有:https://pan.q删掉憨子uark.cn/s/75a5a07b45a2