Files
rikako-note/分布式事务/seata/seata.md
2025-08-27 10:25:59 +08:00

5.7 KiB
Raw Blame History

seata

seata作为兼具高性能和易用性的分布式事务解决方案适用于微服务架构。

在使用seata的系统中事务隔离级别如下

  • branch transaction/local transaction在seata系统中分支事务/本地事务的隔离级别为read committed
  • global transaction在seata系统中全局事务的隔离级别为read uncommitted
    • global transaction隔离级别为read uncommitted的含义如下在全局事务尚未提交时如果分支事务提交则分支事务的修改对分布式系统外的其他事务可见

故而在分布式系统中若全局事务的隔离级别为read uncommitted且没有其他机制用于修复该问题其将会造成如下问题 1

在上图所示中全局事务A和全局事务B对相同的资源R进行了修改并且分支事务A1和分支事务B1都本地提交之后全局事务A回滚全局事务B提交那么A无法将资源R回滚到一个合适的状态例如A1先对R进行修改B1后对R进行修改如果将R恢复到A1修改之前那么B1对R的修改就会丢失

Seata Global Exclusive Write Lock

Seata Global Exclusive Write Lock的代码实现位于TC(Transaction Coordinator) module中RMResource Managermodule将会在需要获取global lock时对TC module进行请求进而保证事务之间的写隔离。

故而Seata Global Exclusive Write Lock会在TC module中被实现并在RM module中被使用。

TC - Global Exclusive Write Lock Implementation

在TC module中RpcServer用于处理communication protocol related logic而TC module实际的处理逻辑则由DefaultCoordinator进行处理。

DefaultCoordinator中包含了TC module所有向外暴露的方法例如

  • doGlobalBegin: 创建全局事务
  • doGlobalCommit: 提交全局事务
  • doGlobalRollback: 全局事务回滚
  • doBranchReport: branch transaction状态report
  • doBranchRegisterbranch transaction注册
    • 在AT中branch register会在local transaction提交时进行执行brach register时会实际占用global exclusive write lock
  • doLockCheckglobal exclusive write lock校验

实际上,上述方法都会被委托给DefaultCore来执行

在TC端的实现中所有获取锁校验锁的请求都最终会被LockManger执行所有关于global exclusive write lock的设计都被维护在DefaultLockManagerImpl中。

RM - Global Exclusive Write Lock Usage

在RM module中主要会使用两个global write lock相关的方法

  • 校验是否global lock可以被获取
  • 注册transaction branch并实际获取global lock

在RM端针对global exclusive write lock的check和获取大多通过Statement和Connection的代理对象来实现。例如ConnectionProxy.commit中调用registerBranch从而实现对lock的实际占用。

global write lock的释放和RM无关当全局事务提交时全局事务相关的global lock将会自动被TC module释放。当注册分支事务之前会检查global lock状态确定在branch register的过程中不会发生锁冲突。

当执行update、insert、delete语句时在执行前后都会以undo log的形式生成data snapshot并且生成快照的形式会基于select ... for update

在本地事务执行提交操作时会执行branch register操作该操作中会向TC module发送请求要求占用global write lock。

故而通过global write lock机制seata能够保证全局事务未提交前分支事务占用的锁资源并不会被释放全局事务外的其他事务想要访问数据时首先需要校验是否global exclusive write lock已经被占用上述流程能够保证全局事务能够正确的回滚。

但是在全局事务提交前其他事务必须等待global exclusive write lock的释放这种等待会带来性能损耗。

Read Committed && Read UnCommitted

在seata系统中local transaction/branch transaction的事务隔离级别和数据库实例的默认隔离级别一致例如在mysql中默认为repeatable read但是seata系统中对于global transaction,其事务隔离级别为read uncommitted作为全局事务G1中的分支事务L1其在L1提交但是G1尚未提交的场景下L1对数据库造成的修改对全局事务G2仍然可见。

故而seata中全局事务的隔离级别为读未提交

select ... for update to apply global exclusive write lock

在seata系统中如果特定场景下需要将全局事务的隔离级别改为读已提交,可以使用select ... for update来实现。

在seata-AT的实现中对于select ... for update语句,其会在ConnectionProxy执行时校验是否可获取global write lock。如果当时global write lock被其他全局事务持有那么当前select ... for update会进行重试。当重试次数达到上限时,会抛出异常,如此,可以保证全局事务的读已提交,当全局事务尚未提交/回滚时会持有global write lock其他全局事务无法获取相同数据的global write lock。