粉粉蕉的笔记本粉粉蕉的笔记本
  • JAVA

    • 代码笔记
    • Java8实战
    • 分布式事务实战(Seata)
    • 模板引擎(FreeMarker)
    • SpringSecurity
    • Maven
  • PYTHON

    • 概述
    • python3
    • python3(菜鸟教程)
    • pandas
    • numpy
    • matplotlib
  • 中间件

    • Kafka
    • RocketMQ
    • Redis
    • MongoDB
    • Elastic Search
  • 数据库

    • Mysql
  • 前端

    • Vue学习笔记
    • 前端常见问题汇总
  • 设计模式
  • 大数据

    • 概览
    • Hadoop
    • Hive
  • 机器学习

    • 机器学习概览
  • openclaw实战笔记
  • linux命令速查
  • windows命令速查
  • Docker笔记
  • kubernetes学习笔记
  • kubernetes实操笔记
  • 运维工具大全
  • git操作宝典
  • 概率论
  • 线性代数
  • 统计学
  • 金融知识学习
  • 聚宽
  • 因子分析
  • 后端

    • JAVA基础
    • JAVA多线程
    • JVM
    • 分布式相关
    • 数据库
  • 前端

    • HTML
    • CSS
    • JAVASCRIPT
    • VUE
    • 网络
    • 前端工程化
    • nodejs
  • 健身

    • 笔记
    • 训练计划
  • 读书笔记

    • 《深度学习》
  • 其他

    • RSS
    • 资源导航
    • 医保
    • 装修攻略
我也想搭建这样的博客!
🚋开往
  • JAVA

    • 代码笔记
    • Java8实战
    • 分布式事务实战(Seata)
    • 模板引擎(FreeMarker)
    • SpringSecurity
    • Maven
  • PYTHON

    • 概述
    • python3
    • python3(菜鸟教程)
    • pandas
    • numpy
    • matplotlib
  • 中间件

    • Kafka
    • RocketMQ
    • Redis
    • MongoDB
    • Elastic Search
  • 数据库

    • Mysql
  • 前端

    • Vue学习笔记
    • 前端常见问题汇总
  • 设计模式
  • 大数据

    • 概览
    • Hadoop
    • Hive
  • 机器学习

    • 机器学习概览
  • openclaw实战笔记
  • linux命令速查
  • windows命令速查
  • Docker笔记
  • kubernetes学习笔记
  • kubernetes实操笔记
  • 运维工具大全
  • git操作宝典
  • 概率论
  • 线性代数
  • 统计学
  • 金融知识学习
  • 聚宽
  • 因子分析
  • 后端

    • JAVA基础
    • JAVA多线程
    • JVM
    • 分布式相关
    • 数据库
  • 前端

    • HTML
    • CSS
    • JAVASCRIPT
    • VUE
    • 网络
    • 前端工程化
    • nodejs
  • 健身

    • 笔记
    • 训练计划
  • 读书笔记

    • 《深度学习》
  • 其他

    • RSS
    • 资源导航
    • 医保
    • 装修攻略
我也想搭建这样的博客!
🚋开往
  • 分布式中间件

分布式中间件

⭐分布式系统有哪些组件?

  • 网关(Gateway)
  • 微服务应用(Microservice)
  • 消息队列(Message broker)
  • 数据库(DB)
  • 分布式缓存
  • 分布式锁
  • 分布式事务

通过以下中间件实现:Spring Cloud APP、Nginx、Zookeeper、RabbitMQ、Kafka、Netty、Dubbo等。

Zookeeper的应用场景

略

Kafka的应用场景

略

⭐网关

nginx的原理及配置

略

⭐分布式应用

企业级常见架构

  • SSM(Spring、SpringMVC、Mybatis)
  • SpringBoot、Dubbo、Zookeeper
  • SpringCloud

什么是UMP系统

UMP系统是由阿里巴巴提出的一套云数据库解决方案。 用到的开源组件包括:

  • mnesia(分布式数据库管理系统)
  • LVS(Linux虚拟服务器)
  • RabbitMQ(消息队列服务器)
  • Zookeeper(协同工作系统)

springcloud应用有哪些组件

  • Eureka(服务注册与发现)
  • Ribbon(负载均衡,在RestTemplate上加@LoadBalance)
  • Feign(负载均衡)
  • Hystrix(熔断器)
  • Zuul(网关)
  • Config(配置)

什么是幂等性?如何保证幂等性?

幂等性满足如下条件:

  1. 请求后对资源没有副作用;(如select操作)
  2. 第一次请求的时候对资源产生了副作用,但是以后的多次请求都不会再对资源产生副作用;

保证幂等性的方法:

  1. 请求被处理之后,有地方将结果ID保存起来(例如支付请求,支付完成后将订单ID与支付请求关联起来)
  2. 请求被处理之后,有地方将结果状态保存起来(例如支付请求,支付完成后将订单状态改为“已支付”)

Eureka Client调用Server的服务的流程

  • Eureka Server启动时,会注册信息到Registry(注册中心);
  • Eureka Server会定期向注册中心发送心跳信息(每30s),表明自己可用;
  • Eureka Server发送心跳的同时,会获取最新的注册表信息;
  • 因此,集群里可用的Eureka Server都维护着一张注册表(虽然同一时间内注册表数据可能不一致)
  • Eureka Client第一次调用服务时,会先从Registry(注册中心)获取服务提供者地址(注册表),并缓存到本地;然后取其中一个Server进行调用。下次调用则可直接调用那个Server的服务;
  • Eureka Client也会定期去Server端更新注册表;
  • 当注册表中Eureka Server有多个时,Eureka Client会通过 Ribbon 自动进行负载均衡。
  • 当Client发现调用的Server宕机时,Client会重新从本地的注册表中取新的Server调用地址,并调用。

Eureka服务调用失败后,有哪些处理方案

  • 熔断(默认状态下,当某个服务接受的20个请求里有50%都失败时,触发熔断,再请求该服务会直接返回失败,直到5s后,重新检测是否该打开该服务)
  • 降级(当服务熔断后,客户端调用微服务失败,此时客户端自己准备一个Fallback函数,返回一个缺省值或者报错)
  • 限流
  • 排队

心跳机制 & 注册中心的剔除机制、自我保护机制

  • 心跳机制:client每30s向server发送心跳数据
  • 剔除机制:server一定时间内(默认90s)没有接收到心跳数据,则认为该client已下线,会从自己的缓存中移除该client实例的信息
  • 自我保护机制:
    • 触发开启:server检查15分钟以内所有Eureka实例的正常心跳比,若低于85%,开启自我保护模式
    • 开启状态下:
      • 发现长时间没发送心跳的client,也不会对其进行剔除;
      • 仍然能接收client的注册,但不会同步到其他server中;
      • 待网络正常后,才将client的注册信息同步到其他server中。

Eureka启动一个服务,客户端是怎么从注册中心发现这个服务的,流程说一下

Eureka Client在注册的同时,会启动一个轮询,该轮询会定期从注册中心获取其他服务的信息(IP、port、实例id等),并缓存起来; 调用服务时便会直接从缓存中获取服务的信息。 调用方法:

  1. Ribbon参与时,根据spring.application.name:http://eurakaclientsample1/sample/getData
  2. Ribbon没有参与时,根据IP+端口:http://localhost:10000/sample/getData

如何让Ribbon参与?在RestTemplate上添加@LoadBalance注解。

zookeeper和eureka的区别,以及cap原则

CAP原则:

  • Consistency(一致性):分布式系统中每个节点中的数据是否总是一致
  • Availability(可用性):分布式系统中,部分节点挂掉了,这个集群是否还能使用
  • Partition tolerance(分区容错性):因某些原因,导致某些机房上部署的系统与其他系统不能通信(不连通),则这些机房便形成了“分区”。分区容错性便是指如果形成了“分区”,如何保证集群的一致性和可用性。

若要满足”分区容错性“,办法是将不同机房中的数据备份到其他机房的节点上。这样数据分布在各个机房中,某个机房挂了,该数据还有副本提供访问;但这样会带来一致性问题。

若要满足”一致性“,每次写操作后,要等待其他节点全部写成功,然后才能读;但这样又会带来可用性问题。

因此,分布式系统一般只能满足CAP中的两个原则。而分区容错性又是必须的,所以一般分布式系统都是再C和A中权衡。

eureka -->AP,即高可用,但不满足一致性 如何体现是AP? Eureka Server每个节点都是平等的,每台Server都维护着Server信息注册表,集群中只要有一台服务Server没有宕机,集群也是可用的;

zookeeper -->CP,即数据一致,但不满足高可用 如何体现是CP? zookeeper server集群至少需要3台服务器(leader选举算法需要)。 zookeeper server集群中的节点分为leader和follow节点。 当leader宕机时,集群需要重新选出leader,此时的集群暂时不可用。

cas算法

略

⭐消息队列

rabbitmq有哪些组件,项目中怎么用的,为什么这么用

主要有生产者、消费者、队列、还有交换机。

用法:

  1. 异步。可以将函数调用中某些非关键操作异步化。
  2. 解耦。当发现某个函数以后可能会发送别的消息到其他系统时,可以用消息队列的模式设计。

⭐分布式数据库

1.为什么需要分布式数据库?分布式数据库的优点有哪些?

当数据库遇到以下问题,便要考虑对数据库进行扩展:
1.容量不足
2.性能变差

扩容的方案:当遇到以上问题,可以通过以下方式解决:
1.升级服务器的CPU、硬盘、内存等方式解决(这种方式称为scale-up)。
2.采用分布式数据库(这种方式称为scale-out)

采用分布式数据库的优点:
灵活,方便,上限高

2. 什么时候该分库分表?

当单表数据量达1000w或100G时

3. 有哪些分库分表的方法?

分库分表常用中间件: shardingsphere(当当,有sharding-proxy、sharding-jdbc、sharding-sidecar三种解决方案) Atlas(360) Cobar(Alibaba,已停止维护) Mycat(Alibaba,需要部署代理服务器)

两种方式:垂直切分和水平切分

垂直切分:

(1)垂直分库:将一个数据库切分为多个数据库。所有表也被分类到不同的数据库里。在分类时,将关联度低的表存储到不同的数据库中。 (2)垂直分表:对某个字段太多的表进行拆分,拆分成两个甚至多个表,其中每个表只有部分的字段。

优点: 解决业务层面的耦合,业务清晰; 缺点: 部分表无法join; 需要处理分布式事务; 仍然存在单表数据量太大的问题。

水平切分:

(1)库内分表:当某个单表数据量太大时,拷贝多个该表(有同样的列),将这些数据按某种条件分布到这些表中,从而使单个表的数据量减少。

(2)分库分表:将单表的数据库分到其他机器的表中(与该单表有同样的列)。

优点: 减少单表的数据量; 应用端改造较少? 缺点: 难以保证事务一致性; 跨库的关联查询性能较差;

4.水平切分后,同一张表的数据会被分到多个库/多张表中。有哪些数据分片的规则?

1.根据时间区间或ID区间区分。 例如,按时间区间区分,将数据分为历史数据和热点数据,即“冷热数据分离”。业务功能上只提供热点数据的查询。

优点:易于扩展,当想对集群扩容时,只要增加机器,无需对其他分片的数据进行迁移。 缺点:热机会被频繁读写,冷机则很少被查询,导致资源的浪费。

2.根据数值取模 采用hash取模的方式,将数据平均分到不同的表中。

优点: 不易出现热点数据和并发访问的瓶颈; 缺点: 若集群想要扩容时,需要对分片的数据进行迁移(用一致性hash算法可避免该问题);

5.分库分表带来的问题

  1. 分布式事务 当在一个事务中更新数据时,可能需要同时对不同库的不同表进行更新,此时会面临跨库事务的问题。

解决方案:XA事务、两阶段提交。

  1. 跨节点join查询 不同库中的表不能再进行sql join查询了。

解决方案:

(1)全局表:一些大部分表都会用到的表(字典),为了避免跨库join查询,可以在每个数据库都保存一份这个表。

(2)字段冗余,直接避免sql join查询;

(3)数据组装:分开查询,并在代码层面对数据进行组装;

(4)ER分片:将有关联关系的表放到同一个分片; 3. 跨节点分页、排序问题

  1. 分库分表需要单独设计全局主键。常见主键生成策略: (1)UUID(32个16进制字符,即0-f); (2)专门创建一个生成主键的表。 (3)snowflake分布式自增ID算法。

  2. 数据迁移、扩容问题

⭐缓存

redis常用数据类型及使用、缓存雪崩及缓存穿透相关解决方案

  • string(key-value),可保存字符串和数字
    • 增/改
      • 普通增 SET key value
      • 设置过期时间 SETEX key seconds value
      • 增加多对键值对 MSET key value key value...
      • 自增一 INCR key
      • 自增N INCRBY key increment
      • 自减N DECR key
    • 删
    • 查
      • 普通查 GET key
      • 查子字符串 GETRANGE key start end
      • 返回多个值 MGET key key ...
  • hash(哈希表)
    • 增
      • 往哈希表插入键值对 HSET key field value
      • 插入多对键值对 HMSET key field value field value...
      • 自增N HINCRBY key field increment
    • 删
      • 删除键值对 HDEL key field field ...
    • 查
      • 查某个键对应的值 HGET key field
      • 查所有键值对 HGETALL key
      • 查所有键 HKEYS key
      • 查所有值 HVALS key
  • list(数组)
    • 增
      • 插入多个值到列表头部 LPUSH key value value ...
      • 插入多个值到列表尾部 RPUSH key value value ...
      • 通过索引修改值 LSET key index value ...
    • 删
      • 移出并获取第一个元素 LPOP key
      • 移出并获取最后一个元素 RPOP key
    • 查
      • 查找数组中第i个元素 LINDEX key i
  • set(集合)
    • 增
    • 删
    • 查
  • zset(有序集合)
    • 增
    • 删
    • 查

1.缓存雪崩

缓存雪崩是指,如果所有key的失效时间一致,便会造成在某一时间段所有key失效;此时查询请求会直接去到数据库中。若请求太多甚至会使数据库挂掉。 处理方法:为key的失效时间加个随机值。

2.缓存穿透

缓存穿透是指,用户不断查询缓存中没有的数据,导致请求直接去到数据库中。 处理方法: 1.增加参数校验,不符合规格的入参直接返回报错。 2.Redis自带的布隆过滤器。

3.缓存击穿

与缓存雪崩类似,缓存击穿是有一个Key并发特别大,当该key失效时,大量的请求直接去到数据库,拖垮数据库的性能。 处理方法: 1.设置热点数据永远不过期。 2.加上互斥锁。

⭐ 分布式锁

1.什么时候需要分布式锁

分布式锁的使用在分布式系统中较为常见,当某个变量需要被不同机器上部署的系统共享使用时,就需要用到分布式锁来控制共享变量的访问,尽量做到不出现数据一致性问题。

2.如何实现分布式锁?

  1. 基于数据库实现分布式锁; 创建一个表,表id即为锁。插入一条数据就是一次获取锁的操作。 利用了主键唯一的特性,当已获取了id为1的锁后,再次获取(即插入id=1的数据)会报错,通过此机制实现分布式锁。

  2. 基于缓存(Redis等)实现分布式锁; 使用redisson框架。

  3. 基于Zookeeper实现分布式锁。 使用zk的临时节点(set -e /lock/...)。 临时节点是当session关闭后,节点会被删除。因此可以当做分布式锁来用。

⭐分布式事务

1.有哪些事务的解决方案?有哪些分布式事务的解决方案?

单数据库事务: 每种商用数据库基本上都有自己的事务框架。

分布式事务: 多个数据库共用一个事务,全部操作成功则提交事务,若其中一个失败则全部需要回滚。

有以下几种实现分布式事务的模式:

强一致性(严格保证ACID原则)

  • 2PC(两阶段提交)
  • 3PC(三阶段提交)
  • TCC()

最终一致性(不保证一直保持ACID原则,但最终总会达到ACID)

  • 本地消息表
  • 消息事务(MQ)
  • 最大努力通知

先从强一致性的模式开始说。

2PC模式 原理:

假设某个函数需要向N个数据库插入数据,会经历以下两个阶段。

准备阶段(prepare): 各个数据库开启自己的事务,执行插入语句; 执行完后,不提交,而是通过XA接口告诉事务管理器已准备好(prepare);

提交阶段(commit): 当所有数据库已准备好(prepare),事务管理器才通过XA接口告诉所有数据库,可以提交事务(submit); 反之,若有某个数据库没有返回“准备好(prepare)”,则事务管理器告诉所有数据库,需要回滚事务(rollback)。

优点:

  1. 能保证强一致性
  2. 现实分布式事务的耗时相对比较少(只需要一次prepare、一次commit即可)

缺点:

  1. 同步阻塞资源。分布式事务开启期间会锁住资源,导致其他事务需要等待。
  2. 单点故障。当某节点参与分布式事务时突然宕机,没提交prepare,则其他节点都会处于等待commit状态。
  3. 数据不一致。当事务管理器接收到所有prepare,并返回submit(可以提交)时,部分节点宕机,则会导致实际上有的事务没有被提交,导致数据不一致。

3PC模式 原理:

在2PC的基础上,增加了询问阶段;且增加了“超时没接到回复则默认失败”的机制。

询问阶段(CanCommit): 【事务管理器】 事务管理器向各个参与者发出CanCommit的询问,问是否可以顺利执行事务; 【参与者】 参与者觉得可以,则返回yes;不可以则返回no。

预提交阶段(PreCommit):

【事务管理器】 两种情况。

  1. 事务管理器接收到所有参与者的回复都是yes,则向所有参与者发送PreCommit消息;

  2. 有参与者回复no,或者等待参与者消息超时,则向所有参与者发送abort消息(中断事务);

【参与者】

  1. 接收到PreCommit:就会像2PC的准备阶段一样,开启事务,执行SQL语句,并将undo和redo记录下来; 参与者执行完后,执行成功则返回preCommit ACK;执行失败则返回no;

  2. 接收到Abort:执行事务的中断。

  3. 超时没接收到事务管理器的回复:执行事务的中断。

提交阶段(doCommit): 【事务管理器】 当所有参与者都返回ACK,才进入到该阶段。事务管理器向所有参与者发送doCommit请求。

【参与者】 接收到doCommit请求,正式提交语句,并释放占用资源。 提交完后,向事务管理器返回doCommit ack;

若超时没有收到doCommit请求,参与者也会提交语句,并释放占用资源,返回doCommit ack;

【事务管理器】 接收到所有ack后,完成事务。

若没有接收到所有ack,则向所有参与者发送abort消息(中断事务);

【参与者】 收到abort消息后,使用undo日志回滚事务,回滚完后释放所有资源; 回滚完后,返回ack

【事务管理器】 接收到所有ack后,完成回滚。

2PC模式、3PC模式最终都有可能因为宕机、网络问题,导致数据不一致的情况。此时只能用人工补偿(比如SQL脚本检查)去达到最终一致性了。 2PC有相应的支持(XA),3PC没有或者不常用。

XA模式(2PC的实现) XA模式将系统大致分为两个角色:事务管理器(TransactionManager),本地资源管理器(一般指数据库,以下均称为数据库)。 数据库自己可以提供事务,因此,若只对一个数据库进行读写操作的话,只需要使用自己数据库的事务功能即可; 但当需要对不同数据库进行操作时,便需要有事务管理器来协调和管理事务。

  • XA提供接口来支持事务管理器与数据库之间的交互。
  • 商用数据库基本都实现了XA接口。

TCC模式 适合分布式事务中有不提供事务机制的系统参与的情况(例如微服务、文件系统、Redis等)。 TCC也是强一致性,大概原理是,当某个系统执行失败,需要回滚时,这个回滚的实现由开发者通过代码来完成。

原理如下。

  • T for Try(尝试机制): 增加一种预提交的状态,先将资源冻结,或将状态设置为“进行中”;

    这阶段就是开启事务,并执行sql,但不提交;文件系统则是新值内容。

  • C for Confirm(提交): 当所有Try操作成功后,则TCC框架会将所有Try操作冻结的资源释放,或将状态设置为“已成功”;

    这阶段就是直接在数据库commit事务,文件系统则是保存文件。

  • C for Cancel(取消): 若其中一个Try操作失败,则TCC框架会取消所有冻结的资源,或将状态设置为“已失效”

    做一些逆操作。数据库:将原来的值置回去;文件系统:把原来的内容贴回去。

消息队列(MQ)+本地事件表模式 假设有以下情况: 有一个业务需要按以下步骤进行:A->B->C。 其中服务器a负责A,b负责B,c负责C; 这些服务器都会维护一个事件表(同一数据库里的一张表),还有一个定时任务处理器(例如quartz); 步骤A、B、C就是根据事件表和MQ中的事件驱动,一步一步把流程走完。

一开始请求进来,调用服务器a完成A步骤; 【服务器a】 成功:

  1. 服务器a完成并提交A步骤到数据库,并将“A步骤已完成”这个事件写到本地事件表中(有一个事件ID、时间、事件类型);
  2. 定时任务器会将该事件发送到MQ上,并修改本地事件表中事件的状态。 至此服务器a工作完成。

失败:则直接返回失败。

【服务器b】 成功:

  1. 服务器b的定时任务器会监听MQ上的“A步骤已完成”事件;发现有,则写到自己的事件表中;
  2. 定时任务器还会监听自己事件表,如果有“A步骤已完成”事件,则开始调用B步骤的逻辑;
  3. 服务器b完成并提交B步骤到数据库,并将“B步骤已完成”这个事件写到本地事件表中(有一个事件ID、时间、事件类型);
  4. 定时任务器会将该事件发送到MQ上,并修改本地事件表中事件的状态。

至此服务器b工作完成。

失败:

  1. 服务器b若完成不了步骤B,也需要将“B步骤完成失败”这个事件写到本地事件表中(有一个事件ID、时间、事件类型);
  2. 定时任务器会将该事件发送到MQ上,由服务器a来监听该事件并回滚。

【服务器c】 成功:参考b

失败:参考b。也会发送“C步骤完成失败”的事件到MQ;B监听到后回滚并发送“B步骤完成失败”的事件到MQ,如此类推...

  1. 该模式适合无需同步完成的任务,所有步骤都是异步进行的,因此不能达到强一致性,但理论上能达到最终一致性。
  2. 为了避免重复消费,保证幂等性,应该为每个分布式事务都分配一个ID。这样一旦出现重复消费,在插入自己的本地事件表的时候就会报错。
  3. 每个服务器的本地事件表跟自己其他的业务表均在同一数据库中,因此若步骤完成失败了,就可以直接回滚两个表的操作。

可靠消息服务模式 与“本地事件表模式”相似,只不过将所有服务器的事件表都通过一个“可靠消息服务”来维护。

2. Java、Spring中,事务、分布式事务的运用?

Java事务框架:

  • JDBC事务(仅为单个数据库提供事务支持)
  • JTA事务(可理解为Java版XA规范;支持多个数据源的回滚:JDBC连接、JDO、JMS、EJB等)

    JTA只是一套接口,其实现有:atomikos、JOTM

  • JDO事务
  • JPA事务
  • JMS事务
  • Hibernate事务
  • Mybatis事务
  • Spring事务
  • LCN
  • ByteTCC
  • SeaTa

常见分布式事务框架:

框架TCC模式XA模式AT模式(2PC的改良版)saga模式MQ原理
Atomikos---✔---------两阶段提交(2pc)
LCN✔------------
ByteTCC✔------------
Seata✔✔✔✔---

3. 整合Seata

因为Seata框架比较成熟,且支持多种模式,所以我们可以选择。

各模式的优缺点:

项目AT模式TCC模式XA模式
描述会代理Datasource进行数据库操作,2PC模式的改良版不会代理应用的数据库操作X/Open组织定义了分布式事务接口,Oracle、mysql等厂商进行具体的实现
一致性最终一致性强一致性
整合方法@GlobalTransactional + undo_log(事务回滚日志表)@LocalTCC、@TwoPhaseBusinessAction、定义3个接口对应3个阶段@GlobalTransactional
优点1无侵入性,很少分布式事务相关代码性能高,框架层面解决了空回滚、幂等性、防悬挂的问题无侵入性,极少分布式事务相关代码
优点2弥补了 XA 模式中资源锁定周期过长的缺点,增加了undo_log 机制,性能更好应用自主程度高,事务参与者不局限于数据库,可延伸至其它组件如:Redis支持任何实现了 XA 协议的数据源
缺点1只能回滚数据库这种资源侵入性高,应用需要以 TCC 规范去编写业务逻辑只能回滚数据库这种资源
缺点2不适合用于单个SQL修改大量数据的场景改造成本大,对于存量业务来说,需要将原本的业务逻辑一分为三性能差
适用场景适用于依靠关系型数据库的保存数据的业务场景对性能有较高要求的业务场景适用于基于 XA 协议设计且无法进行改造的业务场景

AT模式是如何弥补XA模式资源锁定周期过长这个缺点的?
AT模式不锁定资源,而是先生成执行前的数据快照,然后直接执行并提交;
然后记录执行后的数据快照;
一旦需要回滚了,便直接用旧的数据快照覆盖新的即可;

什么是空回滚、幂等性、防悬挂?

简单讲讲AT、tcc、XA 3种模式分别的原理?

参考:https://wu55555.blog.csdn.net/article/details/124510770

  1. AT模式

AT模式中,假设有服务A,服务B,服务C

服务A,标记了@GlobalTransactional,因此服务A属于TM;
服务B、C,被服务A调用,因此是RM;
还有一个Seata-Server,负责全局事务的协调,是TC。

1.1 服务A向TC申请开启全局事务,获得一个全局事务ID(XID); 1.2 调用服务B并带上XID;
1.3 服务B向TC注册,并带上XID,好将服务B与服务A分到同一组;同时获得本地事务ID(BID)
1.4 服务B在提交前,服务B会:1. 申请全局行锁 2. 生成事务前数据快照(before image) 1.5 服务B提交后,还会生成事务后数据快照(after image)
1.6 然后,服务B提交事务执行结果 1.6.1 成功。根据before image,生成回滚SQL保存到undo_log里; 1.6.2 失败。根据after image,判断数据是否被脏读。有则报错,没有则事务回滚,并通知TC让其他本地事务回滚 1.7 服务C同理,按照1.3、1.4、1.5、1.6进行 1.8 服务A提交整体执行结果:(1)成功。TC通知服务A删除undo_log及其他事务管理数据;(2)失败:TM通知服务A所有本地事务回退

  1. TCC模式

TCC模式中,有Try、Confirm、Cancel三个阶段。

假设现在有一个提交订单的场景。提交完订单后需要扣减库存。

2.1 Try阶段

  • 创建订单,并标注为未提交
  • 业务检查(是否有足够的库存扣减)
  • 资源预留(冻结库存,冻结的库存其他业务不能使用)

2.2 Confirm阶段

  • 将订单状态改为已提交
  • 冻结的库存取消冻结,正式扣减

2.3 Cancel阶段

  • 删除未提交的订单
  • 取消冻结的库存

在锁使用的方面,整个实现TCC的过程,实际上是没有用到全局锁的,这是和AT模式另外一个大的区别。
TCC模式更多的是利用本地行锁或者乐观锁、状态区分的形式来实现资源隔离。
因为没有全局锁的限制,所以其速度飞快提升。因此呢TCC模式也就适用于对性能有较高的分布式事务场景。

2.4 建立TCC模式的重试机制

confirm或者cancel方法也出现报错时,为了保证事务的最终一致性,我们应当做好重试机制处理:
比如将请求发送MQ,然后再接收处理。

2.5 幂等性问题

如果扣减库存时多次重试,仍然能保证只扣了1次库存,这种就称为保证了幂等性。

换句话说,操作多次和操作一次的效果一样,就是所谓的幂等。

如何保证幂等性:

  • 添加状态字段,判断是否执行过

2.6 悬挂问题(又叫空回滚)

所谓悬挂问题,就是二阶段模式中,cancel比try先执行。

拿上面的例子,cancel是解冻库存,try是将订单状态改为未提交。

2.6.1 因为网络问题,导致商品服务的try一直卡住,然后报错

2.6.2 TM通知库存服务回滚,执行了cancel方法,解冻了库存;

2.6.3 此时商品服务又好了,执行了try方法,将订单状态改为未提交;

2.6.4 然而事务已经被cancel过了,就不会再执行confirm,也就没有谁再来将资源状态从预处理更新为已处理了。

针对悬挂问题进行防悬挂处理,方案呢就是限制如果二阶段执行完成,一阶段就不能再执行。

当然这些处理呢,seata已经帮我们实现了,这也是使用现成的分布式事务框架的好处。省心!但是我们自己要知道这些问题和原理。

seata中的解决方案是增加一个事务记录表,在cancel阶段最后往事务记录表中插入一条记录(xid-status)标记cancel阶段已经执行过。
此时try阶段进入时发现已经执行过回滚操作,则放弃try阶段的执行

Last Updated: 5/12/26, 10:21 AM
Contributors: dongyz8, Fun_zil