1. 分布式事务的基本概念
定义:分布式事务是指保证多个原子服务的操作要么全部成功、要么全部失败,从而确保数据一致性的机制。
角色:1.事务发起者(TM)发起全局事务,接收TC协调 2.事务协调者(TC)协调所有事务参与者,管理全局事务 3.事务参与者(RM)参与全局事务
全局事务:又称分布式事务,它包含了所有的分支事务
分支事务:类似于单体项目的事务,是指每个服务自己专属的本地事务
2. 分布式事务的常见解决方案
2.1 XA协议
XA协议提交是最经典的分布式事务协议,由协调者和多个参与者组成。整个过程分为两个阶段:
- 准备阶段:协调者向所有参与者发送准备请求,参与者执行完本地事务后但不提交,等待协调者进行结果汇总,等待所有参与者回复 [可以提交] 则继续下一阶段。
- 提交阶段:如果所有参与者都返回 [可以提交] ,协调者广播提交指令,各参与者正式提交本地事务;如果任一参与者返回 [需要回滚] ,协调者广播回滚指令,各参与者回滚事务。
XA协议的优点是原理简单、可直接实现分布式事务;缺点是存在事务挂起、资源空耗,性能低下等问题
2.2 TCC 补偿事务
TCC(Try-Confirm-Cancel)是一种补偿型事务,将每个业务接口都拆分为三个接口:
- Try:尝试执行业务,完成资源预留和业务检查,但不真正提交。
- Confirm:确认执行业务,使用 Try 阶段预留的资源完成真正的业务操作。
- Cancel:取消执行业务,释放 Try 阶段预留的资源。
TCC 的优点是性能较好(没有事务挂起),灵活度高,适合并发量大的场景;缺点是每个业务都需要实现 Try、Confirm、Cancel 三个接口,开发成本较高。
2.3 Seata AT 模式(主流)
Seata 是阿里巴巴开源的一套分布式事务解决方案,目的是在微服务架构中能提供简单好用且高性能的分布式事务服务。其 AT 模式基于2PC提交思想,通过全局锁和 undo log 机制,对业务代码侵入性极低,是目前业界应用最广泛的方案之一。
3. Seata AT 模式的全局事务执行过程
Seata AT 模式的核心角色包括:事务协调者(TC)、事务管理器(TM)和资源管理器(RM)。全局事务的执行过程分为两个阶段:
3.1 第一阶段:业务 SQL 执行与 undo_log 记录
- TM 向 TC 发起全局事务开启请求,TC 生成全局事务 ID(XID),并通过调用链传递到各个微服务。
- RM 拦截业务 SQL,生成执行前的数据快照和执行后的数据快照,并将快照信息写入 undo_ log 表。
- RM 执行本地业务 SQL,提交本地事务,同时向 TC 注册分支事务并上报执行结果。
- 第一阶段结束时,本地事务已经提交,数据对外可见,因此 AT 模式在提交阶段没有长时间的锁持有,性能较好。
3.2 第二阶段:全局提交或全局回滚
- TM 根据业务执行结果向 TC 发起全局提交或全局回滚请求。
- 全局提交:TC 通知各 RM 异步删除所有undo_log表数据,释放全局锁,完成提交。
- 全局回滚:TC 通知各 RM 根据 undo_log 表中的SQL执行前的数据快照生成反向 SQL,将数据恢复为执行前的状态,然后删除 undo_log表数据,释放全局锁。
4. Seata AT 模式如何实现写隔离
写隔离是保证并发事务之间数据不会互相覆盖。Seata AT 模式通过全局锁机制实现写隔离,具体过程如下:
- 在本地事务提交前,RM 会向 TC 申请针对目标数据行的全局锁。全局锁的粒度是行级,锁信息记录在 TC 的锁表中。
- 如果全局锁申请成功,RM 才允许提交本地事务;如果申请失败(说明其他全局事务正在操作同一行数据),RM 会等待重试,直到获取锁或超时。
- 由于本地事务在获取全局锁之后才提交,因此其他全局事务无法同时修改同一行数据,从而实现写隔离。
5. 全局锁与本地锁的区别
本地锁解决的是单个数据库内并发事务的隔离问题,而全局锁解决的是跨服务、跨数据库的分布式并发写冲突问题。AT 模式在本地事务提交前先获取全局锁,再依赖数据库本地锁保证本地事务内部的隔离性。
6. 缓存与数据库不同步,如何解决
缓存与数据库不同步是分布式系统中的经典问题,常见于使用 Redis 等缓存加速读操作、以数据库为最终数据源的场景。
方案一:Cache Aside Pattern (旁路缓存模式) + 重试机制
策略:先更新数据库,再删除缓存。
兜底:如果删除缓存失败怎么办?
消息队列重试:将删除失败的消息发入MQ,后台消费者不断重试删除。
Canal 订阅 Binlog :业务代码只更新DB,利用阿里 Canal 伪装成 MySQL 从节点订阅 Binlog,解析出变更的数据,异步去删除/更新 Redis。完全解耦业务代码。方案二:延迟双删
策略:先删除缓存 -> 更新数据库 -> 休眠N毫秒 -> 再次删除缓存。
原理:第二次删除是为了抹平在“更新DB”期间,其他读请求将旧数据重新加载到缓存中产生的脏数据。
缺点:休眠时间难以评估(需大于读业务耗时),且降低了系统吞吐量。方案三:设置合理的过期时间
无论使用哪种策略,都必须给缓存设置合理的 TTL(过期时间)。
即使上述所有删除缓存的动作都失败了,等 TTL 到期后,缓存自动失效,下一次读请求会重新从 DB 加载最新数据,保证最终一致性。
7. 总结
分布式事务是微服务架构下保证跨服务数据一致性的核心难题。从 2PC到 TCC,再到 Seata AT 模式,每种方案都在一致性、可用性和性能之间做了不同的权衡。Seata AT 模式通过全局锁和 undo_log 实现了对业务低侵入的最终一致方案,是当前实践中的主流选择。同时,缓存与数据库的一致性问题也需要结合具体业务场景,选择合适的更新策略和补偿机制,才能在高并发下保证数据的正确性。