本讲咱们要解决分布式事务这一技术难题,这一讲咱们将介绍三方面内容:

  • 讲解分布式事务的解决方案;

  • 介绍 Alibaba Seata 分布式事务中间件;

  • 分析 Seata 的 AT 模式实现原理。

分布式事务的解决方案

下面咱们先聊一下为什么会产生分布式事务。咱们举个例子,某线上商城会员在购买商品的同时产生相应的消费积分,消费积分在下一次购物时可以抵用现金。这个业务的逻辑如果放在以前的单点应用是很简单的,如下所示。

开启数据库事务
创建订单
会员积分增加
商品库存减少
提交数据库事务

在这个过程中,因为程序操作的是单点数据库,所以在一个数据库事务中便可完成所有操作,利用数据库事务自带的原子性保证了所有数据要么全部处理成功,要么全部回滚撤销。但是放在以微服务为代表的分布式架构下问题就没那么简单了,我们来看一下示意图。

分布式架构下调用关系图

可以看到,商城应用作为业务的发起者分别向订单、会员、库存服务发起了调用,而这些服务又拥有自己独立的数据存储,因为在物理上各个数据库服务器都是独立的,每一个步骤的操作都会创建独立的事务,这就意味着在分布式处理时无法通过单点数据库利用一个事务保证数据的完整性,我们必须引入某种额外的机制来协调多个事务要么全部提交、要么全部回滚,以此保证数据的完整性,这便是“分布式事务”的由来。

在分布式架构中有两种经典的分布式事务解决方案:二阶段提交(2PC)与三阶段提交(3PC)。

二阶段提交

首先咱们分析下二阶段提交的处理过程,下面是二阶段提交中的第一个阶段:事务预处理阶段。

  • 2PC 阶段一:事务预处理阶段

可以看到,相比单点事务,分布式事务中增加了一个新的角色:事务协调者(Coordinator),它的职责就是协调各个分支事务的开启与提交、回滚的处理。以上图为例,当商城应用订单创建后,首先事务协调者会向各服务下达“处理本地事务”的通知,所谓本地事务就是每个服务应该做的事情,如订单服务中负责创建新的订单记录;会员服务负责增加会员的积分;库存服务负责减少库存数量。在这个阶段,被操作的所有数据都处于未提交(uncommit)的状态,会被排它锁锁定。当本地事务都处理完成后,会通知事务协调者“本地事务处理完毕”。当事务协调者陆续收到订单、会员、库存服务的处理完毕通知后,便进入“阶段二:提交阶段”。

  • 2PC 阶段二:提交阶段

在提交阶段,事务协调者会向每一个服务下达提交命令,每个服务收到提交命令后在本地事务中对阶段一未提交的数据执行 Commit 提交以完成数据最终的写入,之后服务便向事务协调者上报“提交成功”的通知。当事务协调者收到所有服务“提交成功”的通知后,就意味着一次分布式事务处理已完成。

这便是二阶段提交的正常执行过程,但假设在阶段一有任何一个服务因某种原因向事务协调者上报“事务处理失败”,就意味着整体业务处理出现问题,阶段二的操作就自动改为回滚(Rollback)处理,将所有未提交的数据撤销,使数据还原以保证完整性。

对于二阶段提交来说,它有一个致命问题,当阶段二某个服务因为网络原因无法收到协调者下达的提交命令,则未提交的数据就会被长时间阻塞,可能导致系统崩溃。

二阶段提交的缺陷

以上图为例,假如在提交阶段,库存服务实例与事务协调者之间断网。提交指令无法下达,这会导致库存中的“飞科剃须刀”商品库存记录会长期处于未提交的状态,因为这条记录被数据库排他锁长期独占,之后再有其他线程要访问“飞科剃须刀”库存数据,该线程就会长期处于阻塞状态,随着阻塞线程的不断增加,库存服务会面临崩溃的风险。

那这个问题要怎么解决呢?其实只要在服务这一侧增加超时机制,过一段时间被锁定的“飞科剃须刀”数据因超时自动执行提交操作,释放锁定资源。尽管这样做会导致数据不一致,但也比线程积压导致服务崩溃要好,出于此目的,三阶段提交(3PC)便应运而生。

三阶段提交

三阶段提交实质是将二阶段中的提交阶段拆分为“预提交阶段”与“提交阶段”,同时在服务端都引入超时机制,保证数据库资源不会被长时间锁定。下面是三阶段提交的示意流程:

3PC 阶段一:事务预处理阶段

  • 阶段一:事务预处理阶段。

3PC 的事务预处理阶段与 2PC 是一样的,用于处理本地事务,锁定数据库资源,当所有服务返回成功后,进入阶段二。

3PC 阶段二:预提交阶段

  • 阶段二:预提交阶段。

预提交阶段只是一个询问机制,以确认所有服务都已准备好,同时在此阶段协调者和参与者都设置了超时时间以防止出现长时间资源锁定。当阶段二所有服务返回“可以提交”,进入阶段三“提交阶段”。

  • 阶段三:提交阶段。

3PC 的提交阶段与 2PC 的提交阶段是一致的,在每一个数据库中执行提交实现数据的资源写入,如果协调者与服务通信中断导致无法提交,在服务端超时后在也会自动执行提交操作来保证资源释放。

通过对比我们发现,三阶段提交是二阶段提交的优化版本,主要通过加入预提交阶段引入了超时机制,让数据库资源不会被长期锁定,但这也会带来一个新问题,数据一致性也很可能因为超时后的强制提交被破坏,对于这个问题各大软件公司都在各显神通,常见的做法有:增加异步的数据补偿任务、日终跑批前的数据补偿、更完善的业务数据完整性的校验代码、引入数据监控及时通知人工补录这些都是不错的补救措施。

讲到这,相比你对 2PC 与 3PC 的分布式事务方案应该有了初步的了解,这里我还是要强调下,无论是 2PC 与 3PC 都是一种方案,是一种宏观的设计。如果要落地就要依托具体的软件产品,在 Java 开源领域能够提供完善的分布式事务解决方案的产品并不多,比较有代表性的产品有 ByteTCC、TX-LCN、EasyTransaction、Alibaba Seata,其中无论从成熟度、厂商背景、更新频度、社区活跃度各维度比较,Alibaba Seata都是数一数二的分布式事务中间件产品,本讲后面的内容将围绕Alibaba Seata的AT模式展开,探讨Alibaba Seata是如何实现自动化的分布式事务处理的。

Alibaba Seata 分布式事务中间件

Alibaba Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。它的官网是http://seata.io/,截止到目前 Seata 在 GitHub 已有 18564 star,最新版本已迭代到 1.4.0,阿里多年的技术沉淀让 Seata 的内部版本平稳渡过了多次双 11 的考验。2019 年 1 月为了打造更加完善的技术生态和普惠技术成果,Seata 正式宣布对外开源,未来 Seata 将以社区共建的形式帮助其技术更加可靠与完备,按官方的说法Seata目前已具备了在生产环境使用的条件。

Seata 提供了多种分布式事务的解决方案,包含 AT 模式、TCC 模式、SAGA 模式以及 XA 模式。其中 AT 模式提供了最简单易用且无侵入的事务处理机制,通过自动生成反向 SQL 实现事务回滚。从 AT 模式入手使用,使我们理解分布式事务处理机制是非常好的学习办法。

Seata 的特色功能

AT 模式是 Seata 独创的模式,它是基于 2PC 的方案,核心理念是利用数据库 JDBC 加上 Oracle、MySQL 自带的事务方式来对我们分布式事务进行管理。说起来有点晦涩,下边我就结合这张 AT 模式方案图给大家介绍,在 Seata 中关于分布式事务到底需要哪些组件,以及他们都起到了什么样的职能。

Seata 组件图

通过Seata组件图我们可以看到三个组成部分:

  • 第一个是事务协调者(TC),它的作用是维护全局和分支事务的状态,驱动全局事务提交或者回滚,这正是前面讲解 2PC 或者 3PC 方案时提到的事务协调者组件的具体实现,TC 由 SEATA 官方提供。

  • 第二个是事务管理器(TM),事务管理器用于定义全局事务的范围,开始全局事务提交或者回滚全局事务都是由 TM 来决定。

  • 第三个是资源管理器(RM),他用于管理分支事务处理的资源,并且报告分支事务的状态,并驱动分支事务提交或者回滚。

这些概念可能有些晦涩,我们通过前面商城会员采购积分的例子进行讲解。

Seata AT 模式执行过程

创建订单调用逻辑

这里我先给出商城应用中会员采购业务的伪代码。

会员采购(){订单服务.创建订单();积分服务.增加积分();库存服务.减少库存();
}

在会员采购方法中,需要分别执行创建订单、增加积分、减少库存三个步骤完成业务,对于“会员采购”来说方法执行成功,则代表这个全局分布式事务需要提交,如果中间过程出错,则需要全局回滚,这个业务方法本身就决定了全局提交、回滚的时机以及决定了哪些服务需要参与业务处理,因此商城应用的会员采购方法就充当起事务管理器(TM)的角色。

而与之对应的在订单服务中创建订单、会员服务中增加积分、库存服务减少库存这些实际产生的数据处理的服务模块,则被称为资源管理器(RM)。

最后就是由Seata提供的Seata-Server中间件则提供事务协调者(TC)这个角色,实施全局事务1的提交、回滚命令下发。

为了方便理解,我画了时序图介绍 Seata 的执行过程。

  • 第一步,在商城应用(TM)与三个服务(RM)启动后自动向事务协调者Seata-Server(TC)进行注册,让 TC 知晓各个组件的详细信息。

  • 第二步,当会员购物时会执行 TM 的“会员采购”方法,当进入方法前 Seata 为 TM 提供的客户端会自动生效,向 TC 发出开启全局事务的请求。

  • 第三步,会员采购方法开始执行,会依次执行 3 个服务的新增订单、增加积分、减少库存,在请求送往新的 RM 时,都会向 TC 注册新的分支事务。这些分支事务在处理时不但向业务表写入数据,还会自动向 Seata 强制要求的 UNDO_LOG 回滚日志表写入回滚 SQL 日志。

以新增订单事务为例:新增订单时执行的 SQL 语句如下:

INSERT INTO order(id,...) values(1001,...)

与之对应的,Seata 的回滚日志是基于 SQL 反向生成,新增订单创建了 1001 订单,那 Seata会对 SQL 进行解析生成反向的回滚 SQL 日志保存在 UNDO_LOG 表,如下所示:

DELETE FROM order WHERE id = 1001

与之类似会员积分会生成加积分的业务 SQL 以及减积分的回滚 SQL。

#加积分
UPDATE FROM points SET point = 180 + 20 WHERE mid = 182
#UNDO_LOG表中的减积分SQL
UPDATE FROM points SET point = 200 - 20 WHERE mid = 182
  • 第四步,当 RM 的分支事务执行成功后,会自动向 TC 上报分支事务处理成功。

  • 第五步,当会员采购方法正确执行,所有 RM 也向 TC 上报分支事务处理成功,在“会员采购”方法退出前,TM 内置的 Seata 客户端会向 TC 自动发起“提交全局事务”请求。TC 收到“提交全局事务”请求,向所有 RM 下达提交分支事务的命令,每一个 RM 在收到提交命令后,会删除之前保存在 UNDO_LOG 表中的回滚日志。

但是事情总会有意外,假设某个 RM 分支事务处理失败,此时 TM 便不再向 TC 发起“提交全局事务”,转而发送“回滚全局事务”,TC 收到后,通知所有之前已处理成功的 RM 执行回滚 SQL 将数据回滚。

比如 1001 订单在第三步“减少库存”时发现库存不足导致库存服务预处理失败,那全局回滚时第一步订单服务会自动执行删除 1001 订单的回滚 SQL。

DELETE FROM order WHERE id = 1001

以及第二步积分服务会自动执行减少积分的回滚 SQL。

UPDATE FROM points SET point = 200 - 20 WHERE mid = 182

Seata AT模式就是通过执行反向 SQL 达到数据还原的目的,当反向 SQL 执行后便自动从 UNDO_LOG 表中删除。这便是 Seata AT 模式的大致执行过程,在这个过程中我们发现 Seata AT 模式设计的巧妙之处,Seata 为了能做到无侵入的自动实现全局事务提交与回滚,它在 TM端利用了类似于“Spring 声明式事务”的设计,在进入 TM 方法前通知 TC 开启全局事务,在成功执行后自动提交全局事务,执行失败后进行全局回滚。同时在 RM 端也巧妙的采用了 SQL 解析技术自动生成了反向的回滚 SQL 来实现数据还原。

在这我也思考过,为什么 Seata 要生成反向 SQL,而不是利用数据库自带的排他锁机制处理呢?翻阅资料后理解到它的设计意图,如果采用排它锁机制会导致数据资源被锁死,可能会产生大量的数据资源阻塞,进而存在应用崩溃的风险。而生成反向 SQL 的方案则是在预处理阶段事务便已提交,不会出现长时间数据资源锁定的情况,这样能有效提高并发量。但这样做也有弊端,在研究时发现 Seata 是工作在“读未提交”的隔离级别,高并发环境下容易产生脏读、幻读的情况,这也是需要特别注意的地方。

小结

本讲我们首先针对分布式事务的 2PC 与 3PC 方案进行讲解,了解了分布式事务的执行过程与两者之间的区别;之后咱们认识了 Alibaba 出品的分布式事务中间件 Seata,最后通过电商会员采购的案例讲解了 Seata AT 模式的处理过程,让我们对 Seata 有了初步了解。在后面的实践篇,我们将本节偏理论的内容进行落地实现,看通过代码如何使用 Seata 处理分布式事务。

  • 来点实战教程:
    【Spring Cloud Alibaba 综合应用:Seata 分布式事务实战教程】

Spring Cloud Alibaba 高级特性 分布式事务:Alibaba Seata 如何实现分布式事务相关推荐

  1. Spring Cloud Alibaba 高级特性 基于 Sleuth+Zipkin 实施链路跟踪体系

    介绍微服务链路追踪的原理: 讲解基于 Spring Cloud Sleuth 实现链路追踪: 构建 Zipkin Server 实现链路追踪的可视化管理. 下面咱们先来介绍什么是微服务链路追踪. 微服 ...

  2. Spring Cloud Alibaba 高级特性 应用性能监控:通过 SkyWalking 实施链路追踪

    上一讲我们掌握了基于 Sleuth+Zipkin 对微服务架构实施基于日志的链路追踪,通过 Sleuth 在微服务应用中附加链路数据,再通过 Zipkin 实现链路数据收集与可视化,从而保证开发与运维 ...

  3. 【Gulimall】Spring Cloud:spring-cloud-gateway、spring-cloud-openfeign,Alibaba的注册+配置中心Nacos

    文章目录 1 Nacos 1.0安装 1.1注册中心 1.2配置中心 2 spring-cloud-openfeign 3 spring-cloud-gateway Spring Cloud官方 li ...

  4. Spring Cloud Greenwich 新特性和F版升级分享

    来源:https://dwz.cn/LkwPsmut 前几天介绍了,关于Spring Cloud Greenwich版本发布的官方博客翻译:Spring Cloud Greenwich.RELEASE ...

  5. java版b2b2c社交电商spring cloud分布式微服务(七)springboot开启声明式事务

    java b2b2c 电子商务社交平台源码请加企鹅求求:一零三八七七四六二六.springboot开启事务很简单,只需要一个注解@Transactional 就可以了.因为在springboot中已经 ...

  6. Spring Cloud Greenwich 新特性和F升级分享

    2019.01.23 期待已久的Spring Cloud Greenwich 发布了release版本,作为我们团队也第一时间把RC版本替换为release,以下为总结,希望对你使用Spring Cl ...

  7. Spring Cloud Edgware新特性之一:解决Eureka中Jersey 1.x版本过旧的问题-不使用Jersey

    为什么80%的码农都做不了架构师?>>>    Spring Cloud是当前炙手可热的微服务开发框架.它的功能强大,组件丰富,设计优雅.目前Spring Cloud还在不断发展之中 ...

  8. java springcloud版b2b2c社交电商spring cloud分布式微服务 (七)高可用的分布式配置中心(Spring Cloud Config)...

    Springcloud b2b2c电子商务社交平台源码请加企鹅求求:一零三八七七四六二六.讲述了一个服务如何从配置中心读取文件,配置中心如何从远程git读取配置文件,当服务实例很多时,都从配置中心读取 ...

  9. Spring Cloud Edgware新特性之八:Zuul回退的改进

    为什么80%的码农都做不了架构师?>>>    Spring Cloud Edgware对Hystrix回退的逻辑进行了一些改进.本文将信息探讨新旧版本的回退操作,并分析的原因及改进 ...

最新文章

  1. 密织“地网” 南充“试水”智慧安防
  2. stm32 交换机芯片_基于STM32的全链路语音交互 - stm32/stm8 - 电子工程世界
  3. jsTree如何自定义节点的icon
  4. innodb中master线程的调度的算法改进(mysql 5.6.26)
  5. 网站爬取工具_浅析阻碍网站内容被蜘蛛抓取的原因有哪些?
  6. [导入][导入][c#]Web开发中Tag的开发技巧
  7. acill排序 java_字符串ASCII码排序
  8. c语言因子优化算法,【代码】求一个数的因数和、求优化、顺便也供新人参考算法...
  9. 小程序中从后台获取内容纯数字、纯字母超出父盒子宽度时不换行 解决方法
  10. 新建SpringCloud电商后台项目
  11. 清理Win10系统C盘的脚本方法
  12. 安装visual studio 2013
  13. 蓝桥杯单片机第十届省赛题程序实现
  14. 阿里云服务器安装WordPress,搭建自己的博客网站
  15. WEB漏洞-逻辑越权之登录脆弱及支付修改
  16. zeppelin使用中的问题汇总
  17. sts导报快捷键_综合技术--sts常用快捷键
  18. java txt数据导入excel,java导入excle文件《如何用java 将txt数据导入excel》
  19. 视频教程-javascript/jquery全过程详解-Java
  20. vmware16安装windows server 2008 VMware Tools

热门文章

  1. mNGS及古细菌DNA检测应用推荐:PCR去污染试剂盒
  2. 随机森林RandomForest回归生物标记预测时间序列
  3. 植物根系微生物组的调控入选中科院科技创新亮点成果筛选
  4. 利用Gephi软件绘制网络图
  5. Python使用matplotlib函数subplot可视化多个不同颜色的折线图、为多个子图添加总标题(main title)、自定义设置主标题字体类型、字体大小、字体颜色等
  6. R语言使用caret包的preProcess函数进行数据预处理:对所有的数据列进行YeoJohnson变换(将非正态分布数据列转换为正态分布数据、可以处理负数)、设置参数为YeoJohnson
  7. numpy使用[]语法索引二维numpy数组中指定指定行之前所有数据行的数值内容(accessing rows in numpy array before specifc row)
  8. R语言使用pwr包的pwr.r.test函数对相关信息分析进行效用分析(power analysis)、在已知效应量(effect size)、显著性水平、效用值的情况下计算需要的样本量
  9. R语言dplyr包数据过滤(filter)基于not in规则实战(not in Filter):基于单数据列not in规则过滤数据行、基于多数据列not in规则过滤数据行
  10. 介绍一下K近邻(KNN)算法,KNeighbors和RadiusNeighbors的差异是什么?各有什么优势?