Seata源码(二十)面试题


铿然架构 | 作者 / 铿然一叶 这是 铿然架构 的第 110 篇原创文章


seata支持的事务模式有哪些?

A:4种模式,分别是AT、XA、TCC、SAGA。

undo日志的生命周期,何时生成,入库,清理?

A:undo日志在SQL执行的前后分别生成before、after镜像,接着在SQL执行后写入缓存;在本地事务提交前将undo日志入库;在本地事务提交之后或本地事务回滚后清理undo日志缓存。

全局锁是否会写undo日志?

A:不会,全局锁的作用是避免和全局事务操作的表一样,同时操作时导致脏写或脏读,它只涉及加锁操作,不会写undo日志。

undo日志入库前会经过哪些处理?

A:会做编码和数据压缩,编码支持Kryo、Protostuff、Fastjson、Fst、Jackson,数据压缩支持ZIP、SevenZ、Deflater、Lz4、Gzip、BZip2。

delete语句的undo日志镜像和insert、update语句有什么不同?

A:delete语句只有before镜像,没有after镜像,insert语句没有before镜像,update语句before镜像和after镜像都有。

undo日志的镜像格式?

A:具体的格式不需要记录,只需要知道核心原理则可。

语句类型 镜像原理
insert 记录插入数据的主键信息,undo时根据主键删除。
update 记录更新前的数据和主键信息,updo时根据这些信息更新回去;同时要记录更新后的数据和主键信息,用于在undo时比较数据是否发生变化,如果没有变化才做undo操作。
delete 记录删除的数据信息,在undo时做插入操作。

undo日志写入失败会如何处理?

A:undo日志写入失败会抛出SQLExection,所有异常都会向上抛出,最后触发全局事务回滚。

undo日志如何保证和业务操作在一个事务内?

A:undo日志和业务操作使用的是同一个connection实例,undo日志在connection做commit前写入,保证和业务操作执行的SQL一起提交。

undo模式的性能影响?

A:增加了新的SQL日志写入,高并发场景肯定会有影响,这个建议做一个性能测试,通过性能评估确定什么场景适合使用。

使用seata时,对异常处理有什么注意事项?

A:发生异常时,seata捕捉了Throwable进行处理,因此所有异常都会捕捉到,哪怕是诸如不需要添加catch块的RuntimeException,因此只需要注意不要自行捕捉异常,进行处理后不继续向上抛则可。

不想使用全局事务,又想在多个微服务调用时避免脏写有什么办法?

A:可以使用全局锁,注意是在分布式事务场景(多个微服务)下使用,如果只有一个微服务,本地事务就可以控制,不需要使用全局锁。

AT模式下,开启全局事务后,嵌套服务如何开启新的全局事务?

例如服务调用顺序A、B、C、D,A和D是一个事务,B和C要开启一个新的全局事务。

A:在B的入口方法上使用GlobalTransactional注解,并将propagation属性设置为Propagation.REQUIRES_NEW。

GlobalTransactional注解和Transactional注解的关系?

A:前者是全局事务注解,后者是本地事务注解,两者不冲突,可以同时使用。

TCC模式下,应该如何实现prepare,commit,rollback方法,才能保证事务一致性?

A:如果要分成多步来实现,可能undo日志是最保险的。网上提到TCC模式的一种实现方法是资源预留,在prepare时预留资源,commit时才实际扣除资源,rollback时删除预留资源。这种方式虽然比什么都不做好,但是commit也存在失败可能,也需要额外的处理机制,也并非什么场景下都适合。

不管哪种实现方式主要考虑点有:

● 实时性,是否要立即给用户返回结果,例如账户充值后要立即告诉用户充值后的余额

● 最终一致性,是立马要保证事务一致,还是最终一致就可以。

以上两点会影响实现方式,根据实际业务述求设计对应的方案,只要能达到目的则可。

如何选择TCC和AT模式?

A:AT模式下每一个分支事务都要写undo日志,全部交给框架去控制,而TCC模式只是提供了控制逻辑(协调执行各个分支事务的prepare、commit、rollback方法),具体的事务控制逻辑由业务实现,更加自由,轻量,例如:

● TCC可以只写更少的undo日志,比如只是在业务调用的入口处,记录一条交易请求日志,后面通过这条交易请求来构造undo日志,不需要每个表的每次操作都记录undo日志,也不需要同时记录before、after镜像,这样大大提高了性能。这样的操作方式在特定场景下完全可以使用(只要满足交易请求能构造出undo日志),而AT模式下的undo日志只是更通用,并且conver了所有表操作的场景,性能没有影响的场景下可以使用。

● 可以决定什么也不做,在整个分布式事务过程中,有的场景下,事务(或者部分分支事务)是必须要完成的,此时TCC模式就可以灵活控制某些分支是否需要实现commit或rollback方法。

简而言之,TCC更加灵活,经过定制后性能可能比AT模式高,但是复杂性高于AT模式,AT模式性能差,通用性高。

AT模式下事务传播级别有哪些,分别怎么处理的?

序号 类型
NOT_SUPPORTED 挂起已有的全局事务,执行当前操作,并返回结果
REQUIRES_NEW 挂起已有的全局事务,并开启一个新全局事务,现有的全局事务继续执行
SUPPORTS 如果全局事务不存在,则执行当前操作,并返回结果
REQUIRED 现有全局事务继续执行
NEVER 如果全局事务存在,则抛出异常,否则执行当前操作,并返回结果
MANDATORY 如果全局事务不存在,则抛出异常

对于事务传播级别,需要思考什么场景会用哪种级别。

如何做到TC高可用?

A:通过K8S部署多副本实现高可用,并且通过服务发现机制和TM、RM通信。

是否要使用分布式事务?

A:分布式事务处理起来要么性能有影响,要么逻辑复杂,如果可以避免应尽量避免,主要手段有:

● 增加可靠性:包括数据库冗余,网络冗余(多网卡,多运营商专线),微服务冗余,减少交易处理失败需要回滚概率。

● 重试机制:如果节点A微服务不可用,可以重试发送到其他节点。并且服务交易要支持幂等性,保证重试时不会重复处理。

● 提供对账机制:特别是外部系统和内部系统,系统和系统之间,如果因为系统/网络不可用导致超时,有限次数重试之后还是失败导致的事务不一致,需要进行交易日志对账,做到最终一致性。

● 异步处理,先发送交易请求并记录下来,异步根据交易请求分步骤去处理,失败了则不断重试,始终失败则人工干预,最终保持一致性。

至于是否使用分布式事务,取决于每种方案下的成本,这个成本包含硬件投入,软件开发/维护,以及运营成本等,要综合考虑。


其他阅读:

萌新快速成长之路
如何编写软件设计文档
JAVA编程思想(一)通过依赖注入增加扩展性
JAVA编程思想(二)如何面向接口编程
JAVA编程思想(三)去掉别扭的if,自注册策略模式优雅满足开闭原则
JAVA编程思想(四)Builder模式经典范式以及和工厂模式如何选?
Java编程思想(七)使用组合和继承的场景
JAVA基础(一)简单、透彻理解内部类和静态内部类
JAVA基础(二)内存优化-使用Java引用做缓存
JAVA基础(三)ClassLoader实现热加载
JAVA基础(四)枚举(enum)和常量定义,工厂类使用对比
JAVA基础(五)函数式接口-复用,解耦之利刃

相关推荐
雷神乐乐13 分钟前
File.separator与File.separatorChar的区别
java·路径分隔符
小刘|18 分钟前
《Java 实现希尔排序:原理剖析与代码详解》
java·算法·排序算法
逊嘘37 分钟前
【Java语言】抽象类与接口
java·开发语言·jvm
morris13144 分钟前
【SpringBoot】Xss的常见攻击方式与防御手段
java·spring boot·xss·csp
七星静香1 小时前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
Jacob程序员1 小时前
java导出word文件(手绘)
java·开发语言·word
ZHOUPUYU1 小时前
IntelliJ IDEA超详细下载安装教程(附安装包)
java·ide·intellij-idea
stewie61 小时前
在IDEA中使用Git
java·git
Elaine2023911 小时前
06 网络编程基础
java·网络
G丶AEOM2 小时前
分布式——BASE理论
java·分布式·八股