当前位置: 首页 > news >正文

分布式会话的演进和最佳事件,含springBoot 实现(Java版本)

一、分布式会话的背景

在微服务架构或集群部署环境下,请求可能落在不同的服务器节点,无法再依赖本地内存来维护用户 Session。因此,需要一种跨节点共享 Session 的机制,这就是 分布式会话管理的核心目标。


二、分布式会话的演进历程

1. 单节点会话(原始方案)

  • 会话存储在内存中,如 Tomcat 的 HttpSession。
  • 缺点:不可扩展节点故障丢失会话

2. Session Sticky(会话绑定)

  • 做法:使用负载均衡策略(如 Nginx 的 ip_hash)将同一用户绑定到固定节点。

  • 优点:不用共享 Session。

  • 缺点:

    • 容错差:节点挂了,Session 丢失。
    • 扩展性差:负载不均衡。

3. Session 复制(共享内存同步)

  • 如 Tomcat 集群通过 DeltaManagerBackupManager 实现 Session 同步。

  • 缺点:

    • 性能开销大(尤其写操作多时)。
    • 网络带宽压力高。

4. 集中式 Session 存储(核心阶段)

  • 统一存储于 Redis、Memcached、数据库等。

  • 优点:

    • 节点无状态,扩容方便。
    • 容错好,支持持久化。
  • 常见技术栈:

    • Spring Session + Redis
    • Shiro + Redis
    • 自定义 Filter 拦截 + Redis
  • 缺点:

    • 读写 Redis 有延迟,需优化缓存与连接池。

5. Token 模式(Stateless Session)

  • 不再使用服务器记录状态。会话状态由客户端持有,常见如 JWT(JSON Web Token)。

  • 特点:

    • 完全无状态,易于扩展。
    • 鉴权速度快,无需访问服务器。
  • 缺点:

    • JWT 不支持撤销。
    • Payload 泄漏风险需加密或签名。
    • 会话失效处理复杂(需结合 Redis 存 token 黑名单等)。

6. 混合模式(最佳实践)

  • 使用 JWT 携带身份信息 + Redis 存储服务端状态(权限、Session 信息等)。

  • 优点兼得:

    • 前端无状态便于认证传输。
    • 服务端掌握可控状态,支持注销、权限变更等。

三、关键技术对比

模式状态位置扩展性容错性性能安全性实时性
Sticky Session服务端
Session 复制多服务端
Redis集中存储Redis
JWT客户端最好最好中(需加密)
混合方案客户端+Redis最佳最佳中上最佳

四、最佳事件(Best Practices)

✅ 实际生产中推荐:

1. Spring Boot 项目:使用 Spring Session + Redis
  • 简单集成,Spring 自动替换原生 Session。
  • 可配置 session TTL,支持自动刷新、分布式环境可控。
2. 高并发微服务:使用 JWT + Redis 双模式
  • JWT 保证 stateless 高性能登录认证。
  • Redis 存储 session 黑名单、权限信息,便于集中管理。
3. 安全性要求高:JWT 签名 + 加密 + Redis 控制权限变更
  • 对 token 加签、加密(如 RSA)防篡改、防泄露。
  • Redis 控制 Token 生命周期、用户禁用、权限升级等事件。
4. 高可用部署:Redis 使用 Sentinel / Cluster + 本地缓存
  • Redis 配合本地 Caffeine/Guava 缓存,减轻访问压力。
  • Redis 节点使用 Sentinel 做主从切换,确保高可用。
5. 重要业务审计:使用 Session ID 记录登录轨迹、权限行为
  • 配合 Kafka/Logstash 进行操作轨迹分析。

五、总结

分布式会话的演进反映了分布式系统对性能、可用性、安全性和扩展性的不断追求。最佳实践通常采用混合模式,兼顾无状态特性与业务控制能力:

推荐组合:JWT(身份标识)+ Redis(状态控制)+ 本地缓存(性能优化)+ Spring Security/Spring Session 集成

六、分布式会话最佳实践之代码实现

Spring Boot + Spring Security + JWT + Redis 的完整分布式会话控制实现


🧱 一、整体架构图

[前端] ⇄ [Spring Boot 接口层 (JWT Auth Filter)] ⇄ [JWT 验签 + Redis 校验] ⇄ [业务接口]

📦 二、Maven 依赖

<!-- Spring Boot -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency><!-- Spring Security -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency><!-- JWT -->
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version>
</dependency><!-- Redis -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

🔐 三、JWT 工具类

@Component
public class JwtUtil {private final String secretKey = "mySecretKey"; // 建议使用 RSA 非对称密钥private final long expiration = 60 * 60 * 1000; // 1小时public String generateToken(String username) {return Jwts.builder().setSubject(username).setIssuedAt(new Date()).setExpiration(new Date(System.currentTimeMillis() + expiration)).signWith(SignatureAlgorithm.HS512, secretKey).compact();}public String getUsername(String token) {return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody().getSubject();}public boolean isTokenValid(String token) {try {Claims claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody();return claims.getExpiration().after(new Date());} catch (Exception e) {return false;}}
}

🔁 四、登录接口

@RestController
@RequestMapping("/auth")
public class AuthController {@Autowired private JwtUtil jwtUtil;@Autowired private RedissonClient redissonClient;@PostMapping("/login")public ResponseEntity<?> login(@RequestBody Map<String, String> login) {String username = login.get("username");String password = login.get("password");//这里要写业务代码查询用户进行数据校验 //获取userId if ("admin".equals(username) && "123456".equals(password)) {String userId= "用户ID";String token = jwtUtil.generateToken(username);RBucket<String> bucket = redissonClient.getBucket("TOKEN:" + userId);bucket.set(token, 30, TimeUnit.MINUTES);return ResponseEntity.ok(Map.of("token", token));}return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid credentials");}@PostMapping("/logout")public ResponseEntity<?> logout(HttpServletRequest request) {String token = request.getHeader("Authorization");if (token != null && token.startsWith("Bearer ")) {String jwt = token.substring(7);String userId= jwtUtil.getUsername(jwt);redissonClient.getBucket("TOKEN:" + userId).delete();}return ResponseEntity.ok("Logged out");}
}

🛡️ 五、JWT 过滤器(拦截器)

@Component
public class JwtAuthFilter extends OncePerRequestFilter {@Autowired private JwtUtil jwtUtil;@Autowired private RedissonClient redissonClient;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)throws ServletException, IOException {String authHeader = request.getHeader("Authorization");if (authHeader != null && authHeader.startsWith("Bearer ")) {String token = authHeader.substring(7);if (jwtUtil.isTokenValid(token)) {String userId = jwtUtil.getUsername(token); RBucket<String> bucket = redissonClient.getBucket("TOKEN:" + userId);String redisToken= bucket.get();boolean exists = bucket.isExists();if (exists && token.equals(redisToken)) {UsernamePasswordAuthenticationToken authentication =new UsernamePasswordAuthenticationToken(username, null, List.of());SecurityContextHolder.getContext().setAuthentication(authentication);}}}chain.doFilter(request, response);}
}

⚙️ 六、Spring Security 配置

@Configuration
@EnableWebSecurity
public class SecurityConfig {@Autowired private JwtAuthFilter jwtAuthFilter;@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers("/auth/**").permitAll().anyRequest().authenticated().and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);http.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);return http.build();}
}

🧪 七、测试方式

  1. 登录

    • POST /auth/login,body:{ "username": "admin", "password": "123456" }
    • 返回 token
  2. 请求业务接口

    • GET /some/api,在 Header 中加 Authorization: Bearer <token>
  3. 退出登录

    • POST /auth/logout,将当前 token 放入 Header

🧠 八、扩展建议(进阶后续会不断填坑)

功能需求建议方案
多端登录互踢Redis 中存储设备ID、时间戳,旧设备 token 作废
Token 黑名单机制Redis 设置黑名单,配合 JWT ID(jti) 做验证
细粒度权限控制搭配 Spring Security 的 @PreAuthorize@Secured 注解使用
Token 刷新机制定期发起 refresh token 请求,更新主 token
Redis 持久化或 Cluster开启持久化,使用 Sentinel/Cluster 高可用

收工

http://www.lryc.cn/news/581751.html

相关文章:

  • 【网络安全】不要在 XSS 中使用 alert(1)
  • 电池预测 | 第33讲 Matlab基于CNN-LSTM-Attention的锂电池剩余寿命预测,附锂电池最新文章汇集
  • 一个简单的脚本,让pdf开启夜间模式
  • 【STM32】通用定时器PWM
  • 李宏毅NLP-8-语音模型
  • 20250706-11-Docker快速入门(下)-构建Nginx镜像和Tomcat镜像_笔记
  • Kotlin lazy 委托的底层实现原理
  • styled-components:现代React样式解决方案
  • 构建下一代智能应用:RAG系统开发深度指南
  • 基于STM32单片机的心率血氧监测系统设计(STM32代码编写+手机APP设计+PCB设计+Proteus仿真)
  • C# 接口(什么是接口)
  • 【机器学习笔记Ⅰ】1 机器学习
  • .golangci.yml文件配置
  • C语言学习(第一天)
  • 求医十年,病因不明,ChatGPT:你看起来有基因突变
  • Gin 框架中如何实现 JWT 鉴权中间件
  • PH热榜 | 2025-07-06
  • 宏定义实现自定义关系运算比较--3
  • 微服务负载均衡全解析:从原理到实践
  • 【王树森推荐系统】召回05:矩阵补充、最近邻查找
  • 操作系统【2】【内存管理】【虚拟内存】【参考小林code】
  • Linux - Linux基础知识
  • 数据挖掘:深度解析与实战应用
  • AI+Web3:从自动化工具到自主经济体的范式革命
  • 电信、移动、联通、广电跨运营商网速慢原因
  • 基于文心开源大模型ERNIE-4.5-0.3B-Paddle私有化部署并构建一个企业智能客服系统
  • SpringBoot基于Mysql的商业辅助决策系统设计与实现
  • Python实现优雅的目录结构打印工具
  • 暑假算法日记第二天
  • 李宏毅genai笔记:LLM内部机制