SpringCloud(28. 分布式会话与分布式事务)
一、背景与问题
在微服务架构中,传统的单体应用会话管理和事务控制机制面临重大挑战。当系统拆分为多个独立服务时,会话状态无法在单个服务中持久化,事务边界也变得模糊。例如:
- 用户登录后,前端可能访问多个微服务
- 订单创建需要同时更新库存和优惠券
- 跨服务的业务操作需要保证最终一致性
这种场景下,传统的Servlet会话管理(基于Servlet容器的HttpSession)和本地事务(JDBC的@Transactional)已无法满足需求。需要引入分布式会话管理和分布式事务解决方案。
二、基本原理
1. 分布式会话原理
分布式会话的核心是将会话数据存储在共享存储中(如Redis、数据库),通过分布式ID生成机制(如UUID、Snowflake)保证会话的全局唯一性。关键机制包括:
- 会话数据存储:将用户会话信息存储在Redis中
- 会话ID生成:使用UUID或分布式ID生成器
- 跨服务访问:通过会话ID关联不同服务的会话数据
- 会话过期机制:通过Redis的TTL设置会话有效期
2. 分布式事务原理
分布式事务的典型解决方案是基于补偿机制的Saga模式,其核心是通过事务参与者协调机制保证最终一致性。主要模式包括:
- TCC(Try-Confirm-Cancel):三阶段事务
- Saga:长周期事务
- Seata:分布式事务中间件
核心思想是通过事务协调器(TC)协调多个资源管理器(RM)的事务操作,确保所有参与方要么全部提交,要么全部回滚。
三、环境准备
# application.yml
spring:
application:
name: distributed-session
redis:
host: 127.0.0.1
port: 6379
cloud:
nacos:
server-addr: 127.0.0.1:8848需要准备的组件:
- Spring Cloud 2021.0.5(2021.0.5版本支持Seata 1.5)
- Redis 6.2.6
- Nacos 2.2.3
- Seata 1.5.3(需配置TC服务器)
四、核心实现
1. 分布式会话实现
// DistributedSessionConfig.java
@Configuration
@EnableRedisHttpSession
public class DistributedSessionConfig {
@Bean
public SessionRepository sessionRepository(RedisConnectionFactory redisConnectionFactory) {
return new RedisSessionRepository(redisConnectionFactory);
}
}// SessionController.java
@RestController
@RequestMapping("/session")
public class SessionController {
@Autowired
private HttpSession session;
@GetMapping("/data")
public String getSessionData() {
return "Session ID: " + session.getId() +
", User: " + session.getAttribute("user");
}
}关键代码解释:
@EnableRedisHttpSession启用Redis会话支持RedisSessionRepository将会话数据存储在Redis中- 通过
HttpSession对象获取会话ID和属性 - 会话过期时间通过
RedisTemplate配置
2. 分布式事务实现(TCC模式)
// OrderService.java
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private InventoryService inventoryService;
@TCC
@Transactional
public void createOrder(Order order) {
// Try阶段
orderMapper.insert(order);
inventoryService.reduceStock(order.getProductId(), order.getQuantity());
}
@Confirm
public void confirmOrder(Long orderId) {
// Confirm阶段
orderMapper.confirm(orderId);
}
@Cancel
public void cancelOrder(Long orderId) {
// Cancel阶段
orderMapper.cancel(orderId);
}
}关键代码解释:
@TCC注解标记TCC事务方法@Transactional确保本地事务@Confirm和@Cancel分别处理确认和取消操作- TCC事务需要在分布式事务协调器(TC)中注册
3. 分布式事务协调器配置
# seata-server.yaml
service:
vgroupMapping:
default:
tc-server-list: 127.0.0.1:9836// SeataConfig.java
@Configuration
public class SeataConfig {
@Bean
public GlobalTransactionScanner globalTransactionScanner() {
return new GlobalTransactionScanner("distributed-session", "default");
}
}关键代码解释:
- 配置Seata服务器地址
- 定义全局事务组名称(distributed-session)
- 初始化全局事务扫描器
- 需要配置Seata Server(TC)作为事务协调器
五、完整案例
电商系统订单创建案例
// OrderController.java
@RestController
@RequestMapping("/orders")
public class OrderController {
@Autowired
private OrderService orderService;
@PostMapping
public ResponseEntity<String> createOrder(@RequestBody OrderRequest request) {
try {
orderService.createOrder(request);
return ResponseEntity.ok("Order created successfully");
} catch (Exception e) {
return ResponseEntity.status(500).body("Order creation failed");
}
}
}// OrderRequest.java
public class OrderRequest {
private String productId;
private Integer quantity;
private String userId;
// 省略getter/setter
}业务流程:
- 用户提交订单请求
- 创建订单(写入数据库)
- 扣减库存(调用库存服务)
- 如果任何步骤失败,触发补偿操作
- 通过Seata协调器管理事务一致性
六、源码解析
1. Redis会话源码解析
// RedisSessionRepository.java
public class RedisSessionRepository implements SessionRepository {
public RedisSessionRepository(RedisConnectionFactory factory) {
this.factory = factory;
this.template = new RedisTemplate<String, Object>(factory);
}
@Override
public Session createSession(Session session) {
// 将会话数据写入Redis
template.opsForValue().set(session.getId(), session);
return session;
}
@Override
public Session readSession(String id) {
// 从Redis读取会话数据
return (Session) template.opsForValue().get(id);
}
@Override
public void delete(Session session) {
// 删除会话数据
template.delete(session.getId());
}
}关键机制:
- 使用RedisTemplate进行序列化存储
- 通过sessionId关联会话数据
- 支持会话过期自动清理
2. TCC事务源码解析
// GlobalTransactionScanner.java
public class GlobalTransactionScanner {
public GlobalTransactionScanner(String transactionName, String groupName) {
this.transactionName = transactionName;
this.groupName = groupName;
}
public void scan() {
// 注册事务参与者
TransactionContext txContext = new TransactionContext();
txContext.setTransactionName(transactionName);
txContext.setGroup(transactionName);
txContext.setResourceList(resourceList);
txContext.setBusinessKey(businessKey);
}
}关键机制:
- 通过TransactionContext注册事务
- 将事务信息传递给Seata服务器
- 支持事务的确认和取消操作
七、进阶使用
1. 分布式事务模式比较
| 模式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| TCC | 需要精确回滚 | 支持补偿机制 | 实现复杂 |
| Saga | 长周期事务 | 简单易实现 | 可能出现数据不一致 |
| Seata | 高并发场景 | 原生支持 | 需要引入中间件 |
2. 性能优化方案
- 使用Redis集群提高读写性能
- 启用Redis的Pipeline批量操作
- 对关键业务操作加缓存
- 使用异步消息队列处理补偿操作
- 调整事务超时时间(默认1分钟)
3. 安全加固方案
- 会话ID采用UUID+时间戳组合
- 使用HTTPS加密传输会话数据
- 设置会话过期时间(建议15分钟)
- 对敏感操作进行二次确认
- 日志记录关键事务操作
八、性能与工程实践
1. 分布式会话性能优化
// Redis配置优化
@Bean
public RedisConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
config.setHostName("127.0.0.1");
config.setPort(6379);
config.setDatabase(0);
config.setTimeout(5000);
RedisConnectionPoolConfig poolConfig = new RedisConnectionPoolConfig();
poolConfig.setMaxIdle(10);
poolConfig.setMaxActive(100);
poolConfig.setMaxWait(1000);
return new RedisConnectionFactory(config, poolConfig);
}优化要点:
- 设置连接池参数
- 优化Redis配置参数
- 使用Pipeline批量操作
2. 分布式事务安全风险
- 数据一致性风险:需要确保所有参与者事务提交/回滚
- 网络分区风险:需设置合理的超时时间
- 事务泄露风险:确保事务上下文正确传递
- 资源竞争风险:需要设置合理的资源隔离
九、常见问题与踩坑
1. 常见错误及解决办法
错误1:会话丢失
// 错误代码
HttpSession session = request.getSession(false);
if (session == null) {
// 错误处理
}解决办法:
// 正确代码
HttpSession session = request.getSession(true);
if (session.getAttribute("user") == null) {
// 会话失效处理
}错误2:分布式事务未提交
// 错误代码
@Transactional
public void createOrder() {
// 业务逻辑
}解决办法:
// 正确代码
@TCC
@Transactional
public void createOrder() {
// 业务逻辑
}2. 常见性能问题
问题:频繁的Redis读写操作
解决方案:
// 使用缓存
@Cacheable("user_sessions")
public Session getSession(String sessionId) {
return redisRepository.readSession(sessionId);
}问题:事务协调器过载
解决方案:
// 调整Seata配置
seata:
server:
service:
vgroupMapping:
default:
tc-server-list: 127.0.0.1:9836
tc-server-list: 127.0.0.1:9837十、最佳实践
1. 推荐方案
- 会话管理:使用Redis+Spring Session实现分布式会话
- 事务管理:对于关键业务使用TCC模式,普通业务使用Saga模式
- 性能优化:启用连接池和Pipeline操作
- 安全加固:设置会话过期时间和HTTPS传输
- 监控告警:集成Prometheus+Grafana监控系统
2. 使用建议
应该使用:
- 电商系统订单创建
- 跨服务的用户认证
- 需要最终一致性的业务场景
不应该使用:
- 低并发场景(可直接使用本地会话)
- 需要强一致性要求的场景(如金融交易)
- 对性能要求极高的实时系统
十一、总结
分布式会话和事务管理是微服务架构中的关键技术挑战。通过Redis实现的分布式会话管理,解决了单体应用的会话存储问题,而基于TCC的分布式事务解决方案则有效处理了跨服务的事务一致性问题。在实际开发中,需要根据业务场景选择合适的模式,同时注意性能优化和安全加固。本文通过完整案例和源码解析,深入探讨了这些技术的实现原理和工程实践,为开发者提供了可直接应用的解决方案。在实际项目中,建议结合具体业务需求选择合适的方案,并持续监控和优化系统性能。
