1.什么是分布式事务?

分布式事务,就是指不是在单个服务或单个数据库架构下,产生的事务,例如:

  • 跨数据源的分布式事务
  • 跨服务的分布式事务
  • 综合情况

在分布式架构中,一次业务调用 可能横跨多个服务 多个数据库, 传统的数据库事务无法保证数据的一致性,需要通过分布式事务来解决

2.分布式事务理论基础?

2.1CAP定理:

  • Consistency(一致性)
    - Availability(可用性)
    - Partition tolerance (分区容错性)
    结论: 分布式架构中 P一定存在, 三者只能满足其二 要么架构是 AP 可用性 ;要么是 CP 一致性
    - AP模式:各子事务分别执行和提交,允许出现结果不一致,然后采用弥补措施恢复数据即可,实现最终一致。
    - CP模式:各个子事务执行后互相等待,同时提交,同时回滚,达成强一致。但事务等待过程中,处于弱可用状态。

    2.2.BASE理论

BASE理论是对CAP的一种解决思路,包含三个思想:

  • Basically Available (基本可用):分布式系统在出现故障时,允许损失部分可用性,即保证核心可用。
  • Soft State(软状态):在一定时间内,允许出现中间状态,比如临时的不一致状态。
  • Eventually Consistent(最终一致性):虽然无法保证强一致性,但是在软状态结束后,最终达到数据一致。


3.Seata的架构

Seata事务管理中有三个重要的角色

  • TC (Transaction Coordinator) - 事务协调者:维护全局和分支事务的状态,协调全局事务提交或回滚。
  • TM (Transaction Manager) - 事务管理器:定义全局事务的范围、开始全局事务、提交或回滚全局事务。
  • RM (Resource Manager) - 资源管理器:管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

image-20210724172326452.png

4.分布式事务的解决方案?

  • XA模式:强一致性分阶段事务模式,牺牲了一定的可用性,无业务侵入
    - TCC模式:最终一致的分阶段事务模式,有业务侵入
    - AT模式:最终一致的分阶段事务模式,无业务侵入,也是Seata的默认模式
    - SAGA模式:长事务模式,有业务侵入
    -MQ + 本地消息表: 将一个大的事务,拆分成若干小的环节,通过可靠性的消息 来保证全部执行
    image-20210724185021819.png

5.如何使用seata?

一、部署seata的服务端(TC 事务协调器)
1.修改配置 : registry.conf
注册中心:让seata将自己的服务信息 注册到nacos中
配置中心:让seata从nacos中 拉取配置
2.配置事务数据库:全局事务表 分支事务表 全局锁表
二、微服务整合seata :
1. 引入seata的依赖 1.4.2
2. 修改微服务的配置 指定从nacos中 拉取seata服务端的信息
3. 在事务的发起方法中 添加全局事务注解@GlobalTransactional

6.seata的工作原理?

使用前提: 1. 数据库必须是支持事务的关系型数据库
2. 必须是java项目,并且用JDBC去访问数据库

@GlobalTransactional 标记的方法说明开启了全局事务,seata会为该方法准备一个拦截器
当该方法被调用时,拦截器中 会向TC端 注册一个全局事务信息(xid)
注册好全局事务后,开始执行每个分支事务:
整体流程分为两个阶段;
1. 执行 每一个分支事务
seata为datasource创建了代理对象,每个服务中操作数据库的方法执行时会创建分支事务
执行分支事务时:
seata会先解析要执行的sql语句 生成前置镜像 ==> 执行sql ==> 生成后置镜像 ,将镜像内容存入undolog日志中, 分支事务执行完毕
2. 根据第一阶段结果,提交 或 回滚
如果所有的分支事务都执行成功, 说明全局事务成功,异步的删除undolog日志即可
如果有任何一个环节失败, 根据undolog日志进行事务回滚
回滚时: 会判断当前数据内容和后置镜像是否一致,一致回滚;不一致,就一直重试

7.分布式事务XID传递原理?

这里SeataHandlerInterceptor实现了HandlerInterceptor,springMVC会在Controller方法调用之前拿到所有注册到容器中的拦截器链去执行其preHandle()方法,将xid绑定到Root上下文中所以全局事务开启时,是由TM来发起的

  1. /**
  2. * @ClassName SeataWebMvcConfig.java
  3. * @Description webMvc高级配置
  4. */
  5. @Configuration
  6. public class SeataWebMvcConfig extends WebMvcConfig {
  7. /***
  8. * @description 解决XID传递问题【重要】
  9. * @return
  10. * @return: com.alibaba.cloud.seata.web.SeataHandlerInterceptor
  11. */
  12. @Bean
  13. public SeataHandlerInterceptor seataHandlerInterceptor(){
  14. return new SeataHandlerInterceptor();
  15. }
  16. /**
  17. * @Description 拦截器
  18. */
  19. @Override
  20. public void addInterceptors(InterceptorRegistry registry) {
  21. super.addInterceptors(registry);
  22. registry.addInterceptor(seataHandlerInterceptor()).addPathPatterns("/**");
  23. }
  24. public class SeataHandlerInterceptor implements HandlerInterceptor {
  25. private static final Logger log = LoggerFactory.getLogger(SeataHandlerInterceptor.class);
  26. public SeataHandlerInterceptor() {
  27. }
  28. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
  29. String xid = RootContext.getXID();
  30. String rpcXid = request.getHeader("TX_XID");
  31. if (log.isDebugEnabled()) {
  32. log.debug("xid in RootContext {} xid in RpcContext {}", xid, rpcXid);
  33. }
  34. if (StringUtils.isBlank(xid) && rpcXid != null) {
  35. RootContext.bind(rpcXid);
  36. if (log.isDebugEnabled()) {
  37. log.debug("bind {} to RootContext", rpcXid);
  38. }
  39. }
  40. return true;
  41. }

8.seata 是否会出现脏读问题?

默认 会出现脏读,因为每个分支事务 真实提交了数据库的事务
如果不想出现脏读,可以在select语句后加上for update,
seata重写了语法解析, 会通过判断全局锁的方式 将隔离级别提升为 读已提交
—> 性能不好

9.seata 是否会出现脏写问题?

不会,虽然有脏读,但如果另一个事务拿到脏数据想修改,还是需要获取全局锁才可以
image-20210724181843029.png

10.seata能否保证高可用?

可以通过搭建集群来解决

11.简述AT模式与XA模式最大的区别是什么?

  • XA模式一阶段不提交事务,锁定资源;AT模式一阶段直接提交,不锁定资源。
  • XA模式依赖数据库机制实现回滚;AT模式利用数据快照实现数据回滚。
  • XA模式强一致;AT模式最终一致