分布式事务 Seata

上一篇文章,我们介绍了分布式事务的基本理论和几种实现方式,现在,我们来了解下Seata
Seata 是阿里开源的基于Java的分布式事务解决方案,共提供了4种模式解决分布式事务场景,分别是AT,XA,TCC,Saga。其中XA,TCC,Saga咱们都介绍过,现在来看下下AT。AT模式是阿里的 GTS(Seata 由 GTS 开源而来)所提出的一种事务模式,这是Seata的一大特色,AT对业务代码完全无侵入性,使用非常简单,改造成本低。我们只需要关注自己的业务SQL,Seata会通过分析我们业务SQL,反向生成回滚数据。

AT包含两个阶段:

  • 第一阶段(业务执行+记录回滚日志)
    业务操作提交时,Seata 会自动拦截 INSERT、UPDATE 等 SQL 操作,在执行这些操作的同时,Seata 会在业务数据库中记录回滚日志(Undo Log),用于恢复数据。
  • 第二阶段(提交/回滚事务)
    如果全局事务成功,Seata 自动清理回滚日志;如果失败,Seata 会根据回滚日志自动恢复数据到操作前的状态。

接下来,我们来看Seata的模块组成

1)TM:事务发起者。负责告知 TC,分布式事务的开始,提交,回滚。
2)RM:资源管理者。管理各个分支事务的资源,每一个 RM 都会作为一个分支事务注册在 TC。
3)TC :事务协调者。负责我们的事务ID的生成,事务注册、提交、回滚等。

本篇我们着重介绍Seata的AT模式

在Seata的AT模式中,TM和RM都作为SDK的一部分集成在业务系统,我们可以认为是Client端。TC是Server端。

工作流程

我们用一个比较简单的业务场景来描述一下Seata AT模式的工作过程。有个充值业务,现在有两个服务,一个负责管理用户的余额,另外一个负责管理用户的积分。当用户充值的时候,首先增加用户账户上的余额,然后增加用户的积分。

AT流程分为两阶段,主要逻辑全部在第一阶段,第二阶段主要做回滚或日志清理的工作。其中,第一阶段流程如下:

图1

积分服务中也有TM,但是由于没有用到,因此直接可以忽略。

1)余额服务中的TM,向TC申请开启一个全局事务,TC会返回一个全局的事务ID。
2)余额服务在执行本地业务之前,RM会先向TC注册分支事务。
3)余额服务依次生成undo log、执行本地事务、生成redo log,最后直接提交本地事务。
4)余额服务的RM向TC汇报,事务状态是成功的。
5)余额服务发起远程调用,把事务ID传给积分服务。
6)积分服务在执行本地业务之前,也会先向TC注册分支事务。
7)积分服务次生成undo log、执行本地事务、生成redo log,最后直接提交本地事务。
8)积分服务的RM向TC汇报,事务状态是成功的。
9)积分服务返回远程调用成功给余额服务。
10)余额服务的TM向TC申请全局事务的提交/回滚。

第二阶段的逻辑就比较简单了。Client和TC之间是有长连接的,如果是正常全局提交,则TC通知多个RM异步清理掉本地的redo和undo log即可。如果是回滚,则TC通知每个RM回滚数据即可。

至此我们已经初步了解了Seata的AT模式是如何实现的了,如果你也和我一样,仔细思考了上述过程,可能会提出一些问题,这边我列举一下我在学习Seata时,遇到的问题,以及我得出的结论。

问题1. Seata如何做到无侵入的分析业务SQL生成undoLog,注册事务分支等操作?

Seata 代理了DataSource,我们可以通过在代码注入一个DataSource来验证我的说法,目前的DataSource 是 io.seata.rm.datasource.DataSourceProxy

图1.png

所有的Java持久化框架,最终在操作数据库时都会通过DataSource接口获取Connection,通过Connection 实现对数据库的增删改查,事务控制。

图2.png

Seata 通过代理的Connection做到了无侵入的生成undoLog,注册事务分支,具体源码可以查看io.seata.rm.datasource.ConnectionProxy

问题2. ConnectionProxy 如何判断当前事务是全局事务,还是本地事务?

通过当前线程是否绑定了全局事务id,在进行全局事务之前,需要调用RootContext.bind(xid);

问题3. 全局事务并发更新
Seata的写隔离级别是全局独占的,事务开启之前,TM会在TC中获取全局锁(用select for update尝试,如果出现锁冲突,那么不断进行重试,直到占本地锁,而后获取全局锁)。锁的的key会以行数据的维度来确定,即同一个数据库中的某个表中的某行数据,在同一时间只会被一个事务操作。
而为了保证高效性,读的隔离级别是Read Uncommitted,当全局事务未提交,而本地数据提交时,对其他全局事务是可见的,不过也没关系,由于全局锁的限制,其他全局事务不能操作该条数据,必须等当前全局事务提交。
举个例子,产品份额有 5W,A 用户买了 2W,份额Branch一阶段完毕(本地事务份额已经扣除 Commit),但是在下单的时候异常了。因为本地事务读已提交,这时候 Seata 允许业务访问该条数据 3W,在 A 用户的份额Branch未回滚成功前,对其他用户可见,但其他用户并不能购买该产品,必须等到产品份额回滚到 5W,其他用户才可以操作产品数据。
当然,如果应用一定要达到Read Committed级别,可以在sql中使用SELECT FOR UPDATE 语句,Seata会锁定持有数据的行锁,直到全局锁是已提交的,才返回。

问题4. 全局事务外的更新
有些全局事务外的方法,它可能并不需要@GlobalTransactional的事务管理,但是我们又希望它对数据的修改能够加入到seata机制当中。那么这时候就需要@GlobalLock了。加上了@GlobalLock,在事务提交的时候就会去checkLock校验一下全局锁。

问题5. @GlobalTransactional 和 @Transactional 同时使用会怎么样
@GlobalTransactional他是负责开启全局事务/提交事务1阶段,说白了@GlobalTransactional 只和Seata-server 交互,而 @Transactional 管理的是本地数据库的事务,所以二者不发生冲突。

问题6. 如果其中某一个事务分支超时未提交,会发生什么
Seata的全局事务超时时间,默认是1分钟,Seata-server 在检测到有超时的全局事务时,会向所有已提交的分支,发起回滚。而超时提交的事务,向Seata-server发起分支注册时,响应结果为事务已超时,或者事务不存在,也会回滚本地事务。

问题7. Seata-client 如何接收Seata-server发起的通知
Seata-client 包含了Netty服务,在启动时Netty会监听端口,并向Seata-server 发起注册。server中存储了client 的调用地址。

与TCC模式性能对比
使用AT 模式时,当事务需要回滚,会根据 Undo Log 进行恢复,而恢复过程可能涉及大量的反向操作,特别是在数据量大或并发高的情况下,性能瓶颈比较明显。而且AT 模式依赖数据库的锁机制来保持数据一致性,因此在某些高并发场景下,数据库可能会出现较大的锁冲突,导致性能下降。

使用TCC模式时,在高并发场景下,Try 阶段的资源预留操作可能导致较多的锁定和资源占用,增加系统负担。

如果你对性能要求极高,并且可以接受较高的开发复杂性,TCC 模式可能是更好的选择;而如果你希望降低开发成本,且业务并发量较低,AT 模式更适合。

总结
对比起TCC等其他事务模型,Seata的AT模式适合大部分业务场景,开发简单。
整个事务的协调、提交或回滚操作,都可以通过AOP完成,开发者只需要关注业务即可。
但是在高并发情况下,数据库锁可能成为瓶颈,尤其是回滚时的性能较差。


引用:
https://www.pianshen.com/article/55481052910/
http://seata.io/zh-cn/blog/seata-at-tcc-saga.html
https://www.jianshu.com/p/e5dc4d07e24e

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,012评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,628评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,653评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,485评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,574评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,590评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,596评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,340评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,794评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,102评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,276评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,940评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,583评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,201评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,441评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,173评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,136评论 2 352

推荐阅读更多精彩内容