本文将会对比Seata与EasyTransaction两个分布式事务的一些高层设计,相信大家会有收获。
Seata的概述
Seata(曾用名Fescar,开源版本GTS)是阿里的开源分布式事务框架,其RoadMap中指出了其希望与社区合作重新构建出一个全面的分布式事务框架。
关于Seata的相关介绍可以看这里,本文不再赘述。虽然其后续路线有所调整,但整体适用。
https://github.com/seata/seata/wiki/%E6%A6%82%E8%A7%88
学习了解Seata后我们可以比对着了解EasyTransaction的架构设计。
EasyTransaction概述
EasyTransaction(后简称ET)的目标也是构建出一个全面分布式事务解决方案,到目前为止其包含TCC,自动补偿(Seata AT),手动补偿,可靠事务消息、Saga事务等等多种形态。
下面将就两个框架在设计上的差异进行分析
核心差异图示
与Seata不同,EasyTransaction对应的图如下:
TC差异
Seata:
- 有独立部署的集中式TC
- RM、TM与TC的交互通过RPC进行
- TC中可以看到每个具体的事务分支,统一协调所有事务分支的提交及回滚
EasyTransaction:
- TC是业务服务进程中的一个模块,并没有独立出来,且存在子事务的服务实例都会调用起TC模块
- 如ServiceA,B,C都有TC,但ServiceD,E没有
- 这里的有无指代的是这一次事务里TC的功能有没有被触发
- TC与TM,RM的交互在进程内进行
- 每个TC只能协调其直接子事务
- 如ServiceA的TC只知道ServiceB及ServiceE的子事务
- 但ServiceB知道还有ServiceC的子事务,因此可以递归协调
- 每个服务实例发起的全局事务,服务实例自身会先尝试一次自协调(大多数都能成功),若自协调失败,则由一个服务实例兜底处理事务协调
Seata有集中式的TC,这样其可以 更容易 实现对分布式事务的监管控,如关于APM、Metrics、统一限流 等等功能。
但在EasyTransaction中的TC形式可以节约TC网络交互时间,在上述Seata的业务图中,ET的形式在两阶段提交中的第一阶段能节约6次 网络来回时间 及 正反序列化时间。
[(registerBranch以及reportBranch)* n个调用层级]
在两阶段提交的第二阶段中,统一提交或者回滚过程中,Seata的形式则是比EasyTransaction快,因为其不需要层级传递下去。视调用层级N的区别,ET形态的第二阶段会比Seata慢 n-1 个网络来回及正反序列化的的时间。
[ (commit或者rollback) * (n-1)个调用层级]
(注:若考虑commit/rollback的次序的话,实际上 seata要按照 业务发生顺序依次提交 或者 逆序回滚,其也为串行,这也为其默认做法,所以实际上ET在这个阶段也会比Seata快一个 网络来回及正反序列化的的时间)
至于 由于数据分散性等等原因APM、Metrics、统一限流 等等功能在ET形式如何实现 的这个问题,我们可以参考普通的RPC是怎么做的,将其纳入统一的RPC管理即可,只是统一管控的力度没有集中式的强大。
同时分散型的TC能 更容易 达到更高级别的可用性,其无需保证TC是否存活,业务服务在则TC在。分散的特征也让压力能在正常业务情况下,能均匀分散到不同的业务实例当中。
TM差异
Seata:
- 独立于Spring/JTA的TransactionManager单独创建了另外一套TransactionManager
- TransactionManager在一个全局事务里只有一个
EasyTransaction:
- 扩展Spring的PlatformTransactionManager(后称PTM)的功能,使其可以管控分布式事务
- 在每个事务分支里都有PTM(Spring原生的事务),但存在子事务的PTM将会挂载扩展分布式事务相关处理以及启动TC模块功能
Seata单独抽象了一套TM,其好处是自由可控,并可以不依赖于任何框架。
ET其TM依赖于Spring的PTM的话,Spring这个框架就变成了使用ET的必选项。但相对的好处就是,所有作用于这个PTM的设施都可以作用于EasyTransaction。
例如Spring的RollbackFor,Transactional,Suspend注解,XML事务切面配置等等都可以直接为EasyTransaction所用。因为ET仅仅只是扩展,因此这些功能都能兼容。甚至于我们要引入JTA,EasyTransaction也能兼容,因为PTM自身就有JTA的实现。
RM差异
Seata:
- 所有参与到全局事务的RM都是平等的存在
EasyTransaction
- 存在主控RM(发起方RM、发起方事务),从事务RM的区别
Seata全局事务里的RM都是平等的存在,整体逻辑上有简单统一的美,但因此其所有的RM都必须能接受两阶段的管控。
但在常规的业务模式中,全局事务开始者(Seata里带TM的那个)的事务,基本都可以在一阶段内获知全局事务应该回滚或者提交,但由于Seata RM都平等的模式,发起方RM必要要用AT模式(记录回滚数据),或者编写TCC的提交回滚方法,这里有一些额外的性能损耗
ET模式里存在事务发起方RM的设定,其只要事务发起方的事务提交成功则全局事务(最终)提交,发起方事务提交失败则全局事务(最终)回滚,因此其事务发起方无需兼容两阶段提交的协议,节约了相关的性能成本。当然,ET的事务发起方RM也可以不写入任何业务,这样的话,就跟Seata的模式一样了。
自动补偿实现差异
Seata:
- 全局锁通过TC保存并实现
EasyTransaction:
- 全局锁通过本地业务数据库保存
Seata通过TC保存全局记录锁引入了更多的复杂度,但其能自由控制锁的实现,能针对场景实现出效率更高的锁。
EasyTransction改造Seata的自动补偿功能,将原有的远程TC依赖改造成了EasyTransaction的分布式TC,并将全局锁实现改造到业务DB中。自动补偿的整体实现复杂度降低了,但性能可能有所下降(未经测试)。
不过Seata相关的实现也在进行中
RPC接口
Seata
- 初期Seata试图维持其核心功能简洁,不涉及任何业务层次RPC的内容
- 后面整合蚂蚁的TCC后框架核心代码开始出现RPC相关内容
- 暴露给用户的是RPC框架原生的接口
- 接口入参出参形式较为自由
EasyTransaction
- RPC是EasyTransaction的一部分,其可更改替换
- 直接暴露给用户使用的并非RPC框架,而是ET的相关接口,RPC仅作为底层通讯的支持
- 接口入参出参形式有限制
EasyTransaction没有采用常规的做法,而是用自己的接口替代原RPC接口的一个原因是这样做能对整个事务过程能 更容易 地把控,其直接与业务交互,知道这一次调用的结果需要马上返回还是可以稍后返回,知道这一次调用是重试还是业务主动触发的,可以通过sdk主动设置RPC框架不进行重试,主动设置使其进行黏性会话以提高效率而不用用户额外单独配置
同时因为RPC是ET的一部分,因此幂等、cancel悬挂等等繁琐重复的问题,能更容易地通过框架自动支持(已经实现),但如果Seata坚持目前轻量级做法的话,将来在实现相关功能时可能会更困难。
当然对业务暴露了ET的接口也算是一种耦合的增强。
动态配置、服务发现、APM等
Seata
- 通过主动配置对接
EasyTransaction
- 利用Spring等现有设施对接
ET利用Spring现有的配置接口进行配置,因此只要相关配置中心对接了Spring,EasyTransaction就能使用。但Seata为了减少对Spring的依赖,因此相关对接需要单独进行。
ET的TC整合到业务服务中,因此TC相关的服务发现只要利用业务自身的服务发现就能完成。而Seata的TC单独部署,因此需要一定的适配工作。
跟上面的原因类似,EasyTransaction的APM等操作只需借用已经整合到RPC框架的APM即可,而Seata需要一定的适配工作
总结
Seata在短短几个月内能积累近万Star除了阿里的技术号召力外,当然还有另外一个原因是分布式事务领域如此普遍且重要,但缺少一个能让小白都能放心无脑使用权威的实现,无疑Seata在如此热烈的社区支持下很有希望能成为这么一个实现。
但在Seata真正成为这个权威实现前,我觉得大家也可以抽空了解下EasyTransaction这个目前功能更为强大、代码更为稳定、已上过生产的实现~
当然以上内容很多都带个人主观偏见,希望各位能补充各种看法,兼听则明!
作者个人公众号
多年金融行业经验,现为某Top2互联网(民营)银行高级搬砖工,曾在两家TOP3股份制商业银行及一家互金创业公司工作(架构、核心业务主程),EasyTransaction作者,欢迎关注个人公众号,在这里我会分享日常工作、生活中对于架构、编码和业务的思考。