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基础(五)函数式接口-复用,解耦之利刃

相关推荐
夏天的味道٥3 小时前
使用 Java 执行 SQL 语句和存储过程
java·开发语言·sql
冰糖码奇朵5 小时前
大数据表高效导入导出解决方案,mysql数据库LOAD DATA命令和INTO OUTFILE命令详解
java·数据库·sql·mysql
好教员好5 小时前
【Spring】整合【SpringMVC】
java·spring
浪九天6 小时前
Java直通车系列13【Spring MVC】(Spring MVC常用注解)
java·后端·spring
堕落年代6 小时前
Maven匹配机制和仓库库设置
java·maven
功德+n6 小时前
Maven 使用指南:基础 + 进阶 + 高级用法
java·开发语言·maven
香精煎鱼香翅捞饭7 小时前
java通用自研接口限流组件
java·开发语言
ChinaRainbowSea7 小时前
Linux: Centos7 Cannot find a valid baseurl for repo: base/7/x86_64 解决方案
java·linux·运维·服务器·docker·架构
囧囧 O_o7 小时前
Java 实现 Oracle 的 MONTHS_BETWEEN 函数
java·oracle
去看日出7 小时前
RabbitMQ消息队列中间件安装部署教程(Windows)-2025最新版详细图文教程(附所需安装包)
java·windows·中间件·消息队列·rabbitmq