Seata 核心实现剖析AT 模式、全局锁、事务协调与 SPI 扩展一、整体架构与核心组件Seata 的架构围绕三个核心角色展开它们之间通过 Netty 通信以 Seata ServerTC为中心进行全局事务的协调。TCTransaction Coordinator独立部署的 Seata Server维护全局事务和分支事务的状态驱动二阶段的提交或回滚。存储端支持数据库global_table、branch_table、lock_table或 Redis。TMTransaction Manager嵌入在发起方微服务中通过GlobalTransactional注解声明全局事务边界负责向 TC 开启、提交或回滚全局事务。RMResource Manager嵌入在每个参与方微服务中管理分支事务的资源如数据库连接向 TC 注册分支事务并响应 TC 的二阶段指令。通信层使用 Netty 实现 TM/RM 与 TC 之间的 RPC 调用序列化支持 kryo、protobuf 等。TC 是无状态的事务上下文持久化在数据库中因此 TC 可以集群部署任意一个节点宕机后其他节点可以从数据库恢复未完成的事务。二、AT 模式的 SQL 拦截与 undo log 生成AT 模式的无侵入性建立在DataSourceProxy和StatementProxy两层代理之上。2.1 数据源代理链在 Spring Boot 集成中Seata 通过SeataAutoDataSourceProxyCreator自动将业务数据源包装为DataSourceProxy。当应用通过dataSource.getConnection()获取连接时实际返回的是ConnectionProxy对象其内部持有真实的物理连接。ConnectionProxy重写了createStatement()和prepareStatement()返回StatementProxy或PreparedStatementProxy由此实现对 SQL 执行过程的全面拦截。2.2 SQL 执行的核心流程以PreparedStatementProxy.executeUpdate()为例核心执行路径如下publicintexecuteUpdate(){// 1. 构建 SQL 识别器解析 SQL 类型、表名、WHERE 条件等SQLRecognizerrecognizerSQLVisitorFactory.get(targetSQL,dbType);// 2. 生成前置镜像执行 SELECT ... FOR UPDATE 查询原始数据TableRecordsbeforeImageexecutor.beforeImage(recognizer);// 3. 执行实际的业务 SQLUPDATE/INSERT/DELETEintrowstargetStatement.executeUpdate();// 4. 生成后置镜像查询变更后的数据TableRecordsafterImageexecutor.afterImage(recognizer,beforeImage);// 5. 构建 undo log 并写入数据库undoLogManager.insertUndoLog(connectionProxy,beforeImage,afterImage);returnrows;}生成前置镜像和后置镜像的前提是 SQL 必须有明确的 WHERE 条件否则SQLRecognizer无法精确识别受影响的行会抛出异常要求修改 SQL。2.3 undo log 的结构undo log 写入业务数据库的undo_log表核心字段包括xid全局事务 ID。branch_id分支事务 ID。rollback_infoJSON 序列化的前后镜像数据包含beforeImage和afterImage以及表结构和行数据。log_status日志状态NORMAL、GLOBAL_FINISHED等。回滚时RM 从rollback_info中解析出beforeImage反向生成 UPDATE 或 DELETE 语句执行。提交时RM 将log_status置为GLOBAL_FINISHED后续由后台任务异步清理。三、全局锁与写隔离机制AT 模式在一阶段就提交了本地事务数据已持久化到数据库必须通过全局锁防止其他全局事务在二阶段完成前修改同一行数据。3.1 全局锁的申请与存储在一阶段本地事务提交前RM 通过ConnectionProxy.commit()触发全局锁申请。核心逻辑在LockManagerImpl中它向 TC 发送GlobalLockRequestTC 将锁记录写入lock_tablelock_table: row_key 表名:主键值 xid 当前全局事务 ID branch_id 当前分支事务 ID如果同一行数据已被其他全局事务锁定TC 返回锁冲突RM 会进入自旋重试默认 10 秒超时后抛出LockConflictException触发全局事务回滚。3.2 全局锁的释放二阶段提交TC 通知 RM 提交RM 在异步删除 undo log 的同时通知 TC 释放该分支持有的所有全局锁。二阶段回滚RM 执行 undo log 的回滚 SQL完成后释放全局锁。3.3 读隔离默认情况下AT 模式的读操作不申请全局锁读的是已提交数据本地事务已提交但全局事务可能尚未结束。如果需要读已提交可以在 SQL 中加SELECT ... FOR UPDATE该语句会触发全局锁申请如果数据被其他全局事务锁定则等待或抛出异常。四、事务协调器 TC 的内部机制TC 是事务的中枢负责全局事务的生命周期管理和分支事务的调度。4.1 全局事务状态机TC 内部通过DefaultCore处理 TM/RM 的请求。全局事务的状态流转如下Begin - (TM) - COMMITTING - (所有分支成功) - COMMITTED - ROLLBACKING - (任一分支失败) - ROLLBACKED状态存储在global_table中事务恢复时根据状态判断应该走提交还是回滚路径。4.2 二阶段异步提交当 TM 发起全局提交时TC 将全局事务状态置为COMMITTING然后通过 Netty 向所有已注册的分支异步发送提交指令。由于 AT 模式一阶段已经提交了本地事务二阶段提交只是删除 undo log 和释放全局锁即使某个分支提交失败TC 也会通过重试机制反复调用直到成功或人工介入。全局事务状态变为COMMITTED后TC 删除对应的global_table记录。4.3 故障恢复与重试TC 宕机重启后会从global_table中查询所有状态非终态COMMITTED/ROLLBACKED的全局事务根据其当前状态重新驱动二阶段。RM 侧也有RetryRollbackingTask和RetryCommittingTask定时检查未完成的分支事务主动向 TC 查询全局状态。五、TCC 模式的防悬挂与幂等TCC 模式下开发者自行实现try、confirm、cancel三个方法。Seata 通过TccActionInterceptor对这些方法进行增强解决两个关键问题防悬挂和幂等。5.1 防悬挂问题场景网络延迟导致cancel先于try到达。如果不处理cancel会被忽略后续try执行后资源没有对应的补偿操作。Seata 的解决方式在TccActionInterceptor中当cancel方法调用时检查branch_table中是否已存在该分支的记录。如果不存在说明try还未执行则先插入一条状态为PhaseTwo_Rollbacked的空分支记录。后续try到来时检查到该记录直接跳过执行。5.2 幂等控制Seata 通过branch_table中的xid和branch_id唯一标识一个 TCC 分支。try方法执行前检查是否已有该分支记录若有则判断状态已try成功则幂等返回已cancel或confirm则根据状态决定行为。开发者也可以通过业务表增加事务状态字段自行实现幂等。六、SPI 扩展点体系Seata 内部大量使用 SPI 机制允许替换核心组件。SPI 加载器为EnhancedServiceLoader支持按order排序、按别名加载、以及从META-INF/services/和META-INF/seata/目录扫描实现。关键扩展点ConfigurationProvider配置源默认从registry.conf或 Spring Boot 配置中加载。RegistryProvider注册中心支持 Nacos、Consul、Zookeeper、Redis 等。StoreMode存储模式支持db数据库和redis。TransactionManager/ResourceManager事务管理器和资源管理器核心接口。LoadBalanceTC 节点间的负载均衡策略默认XID取模。Serializer序列化方式默认 kryo。LockStore全局锁存储默认使用数据库lock_table可扩展为 Redis 实现以获得更好的锁性能。这些扩展点使得 Seata 可以适配不同的注册中心、存储介质和序列化方案同时允许在特殊场景下自定义事务管理器或锁管理器。七、高性能设计要点7.1 一阶段直接提交AT 模式的一阶段直接提交本地事务释放了数据库连接和行锁避免了传统 2PC 的资源长期持有问题。全局事务的耗时主要取决于业务逻辑和远程调用而非锁等待。7.2 Netty 异步通信TM/RM 与 TC 之间通过 Netty 进行异步通信支持请求响应、心跳和重连。多路复用使得单连接能承载大量并发事务TC 单节点可以支撑数万 TPS。7.3 undo log 异步删除二阶段提交时RM 不会同步等待 undo log 删除完成而是异步执行删除并释放全局锁。如果删除失败后台重试机制会反复尝试不影响全局事务的提交。7.4 批量锁申请与释放在高并发场景下RM 可以将多行数据的全局锁合并为一次请求发送给 TC减少 RPC 次数。同样锁释放也支持批量操作。八、总结Seata 通过三层代理DataSourceProxy、ConnectionProxy、StatementProxy实现了对 SQL 的拦截与 undo log 的自动生成使 AT 模式具备了零侵入的特性。全局锁在 TC 端通过lock_table管理解决了一阶段提交后的写隔离问题。TC 的状态机驱动二阶段异步提交与故障恢复保证了最终一致性。TCC 模式通过拦截器处理防悬挂和幂等弥补了业务自行实现补偿的复杂度。SPI 扩展体系则让 Seata 能够灵活适配多种注册中心、存储方案和通信协议。理解这些核心机制的源码实现有助于在生产环境中进行针对性的性能调优和问题排查。推荐阅读Seata 官方文档 - AT 模式Seata Server 源码导读Seata SPI 扩展指南