← 返回首页
🌐

分布式Session:粘性Session、共享Session与JWT

📂 architecture ⏱ 2 min 385 words

分布式Session:粘性Session、共享Session与JWT

分布式Session挑战

单体应用的Session存储在单个服务器内存中,分布式环境下需要解决Session共享问题。常见方案包括粘性Session、Session复制、Session集中存储和无状态JWT。

// Session管理核心接口
public interface SessionManager {
    Session createSession(String sessionId);
    Session getSession(String sessionId);
    void updateSession(Session session);
    void deleteSession(String sessionId);
    void invalidateSession(String sessionId);
}

// Session数据模型
public class Session {
    private String id;
    private String userId;
    private Map<String, Object> attributes;
    private Instant createdAt;
    private Instant lastAccessedAt;
    private Duration maxInactiveInterval;
}

Redis Session共享

使用Redis作为Session存储中心,所有服务器共享Session数据。Spring Session提供了开箱即用的分布式Session支持。

// Spring Session + Redis配置
@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800)
public class SessionConfig {
    @Bean
    public LettuceConnectionFactory connectionFactory() {
        RedisStandaloneConfiguration config = new RedisStandaloneConfiguration("redis", 6379);
        return new LettuceConnectionFactory(config);
    }
}

// 使用Session
@Controller
public class UserController {
    @PostMapping("/login")
    public String login(@RequestParam String username, 
                       @RequestParam String password,
                       HttpSession session) {
        User user = authService.authenticate(username, password);
        if (user != null) {
            session.setAttribute("user", user);
            session.setAttribute("loginTime", Instant.now());
            return "redirect:/dashboard";
        }
        return "login";
    }
    
    @GetMapping("/dashboard")
    public String dashboard(HttpSession session) {
        User user = (User) session.getAttribute("user");
        if (user == null) {
            return "redirect:/login";
        }
        return "dashboard";
    }
}

// 自定义Session序列化
public class SessionSerializer implements RedisSerializer<Session> {
    @Override
    public byte[] serialize(Session session) {
        Map<String, Object> data = new HashMap<>();
        data.put("id", session.getId());
        data.put("userId", session.getUserId());
        data.put("attributes", session.getAttributes());
        return objectMapper.writeValueAsBytes(data);
    }
    
    @Override
    public Session deserialize(byte[] bytes) {
        Map<String, Object> data = objectMapper.readValue(bytes, Map.class);
        Session session = new Session((String) data.get("id"));
        session.setUserId((String) data.get("userId"));
        session.setAttributes((Map<String, Object>) data.get("attributes"));
        return session;
    }
}

JWT无状态方案

JWT将用户信息编码在Token中,服务器无需存储Session状态,天然支持分布式环境。

// JWT工具类
class JwtUtils {
  private static SECRET_KEY = process.env.JWT_SECRET;
  private static EXPIRY = 3600; // 1小时
  
  static generateToken(user: User): string {
    const payload = {
      sub: user.id,
      username: user.username,
      roles: user.roles,
      iat: Math.floor(Date.now() / 1000),
      exp: Math.floor(Date.now() / 1000) + this.EXPIRY,
    };
    return jwt.sign(payload, this.SECRET_KEY);
  }
  
  static verifyToken(token: string): any {
    try {
      return jwt.verify(token, this.SECRET_KEY);
    } catch (error) {
      throw new Error('Invalid token');
    }
  }
  
  static refreshToken(token: string): string {
    const payload = this.verifyToken(token);
    delete payload.iat;
    delete payload.exp;
    return this.generateToken(payload);
  }
}

// JWT中间件
function authMiddleware(req, res, next) {
  const token = req.headers.authorization?.split(' ')[1];
  if (!token) {
    return res.status(401).json({ error: 'No token provided' });
  }
  
  try {
    const payload = JwtUtils.verifyToken(token);
    req.user = payload;
    next();
  } catch (error) {
    return res.status(401).json({ error: 'Invalid token' });
  }
}

// 刷新Token
app.post('/refresh', authMiddleware, (req, res) => {
  const newToken = JwtUtils.refreshToken(req.headers.authorization.split(' ')[1]);
  res.json({ token: newToken });
});

Session方案对比

特性 粘性Session Redis Session JWT
服务器依赖 Redis
扩展性
Session过期 服务器管理 Redis TTL 客户端管理
安全性
跨域支持 困难 支持 支持
适用场景 小规模集群 中大规模 微服务/API