灵魂拷问*5: 从实战角度看分布式事务

不少时候,咱们谈概念,会感受看的时候很明白,过几天就忘光了,缘由就是缺少对应的场景。php


mysql

没有落地支撑的PPT都是耍流氓;sql

没有代码支撑的架构是耍流氓;数据库

没有业务场景支撑的应用方案是耍流氓;缓存

服务器

----大魏语
微信



本篇咱们从实战角度分析分布式事务,因此本文会所有用大白话说清楚。网络


拷问1:为何要用分布式事务?架构

首先,若是一次请求只涉及一个数据库的表,那么不存在分布式的问题。那都叫本地事务(LT)。
app

若是一次请求涉及到两个DB的表,这时候就要用到分布式事务(DT)。主流数据库都支持事务管理。



拷问2:分布式事务的针对对象是什么?

DB?

错,是数据,data。


数据包括:DB、Cache、搜索(ES)。但不少时候,咱们在分布式事务操做最多的是DB。


拷问3:分布式事务(DT)使用什么模型?

CAP是最常被提到的模型。

CAP 理论的定义很简单,CAP 三个字母分别表明了分布式系统中三个相互矛盾的属性:

  • Consistency (一致性):CAP 理论中的副本一致性特指强一致性;

  • Availiablity(可用性):指系统在出现异常时已经能够提供服务;

  • Tolerance to the Partition of network (分区容忍):指系统能够对网络分区。这种异常情 况进行容错处理;

在真实的业务场景中,CAP没法同时知足,可以知足两个就很不错了。所以,仨字母组合,会有:

CA、AP、CP。在实际业务场景中,只有AP和CP。

分布式事务选择AP仍是CP,取决于业务特色,取决于业务容忍度。


网上购物场景用CP。关于这个场景,我仍是用红帽测试代码:coolstore:

图片


若是要购物,会涉及到几个业务模块呢?大体顺序是这样的:

    


也就是说,咱们在电商的一次操做,会涉及:看目录、评分、购物车、减库存、下单等多个功能模块操做。不一样的功能模块由不一样的微服务支撑,有不一样的数据库。这就要保证CP,即数据一致性和分区容忍性。


咱们再看看一个AP模型的分布式事务。

大魏常常写公众号、发公众号。这里面涉及到:

新建图文消息:

写公众号内容:

图片

而后推送给几千人:

图片

在这个分布式事务中,其实更强调吞吐量。不少时候大魏晚上发blog后,都须要10分钟blog才能推送给全部订阅者,就是由于晚上发blog的太多,吞吐量成了瓶颈。



拷问4:分布式事务(DT)必定是异步的么?


错!


同步异步的都有,不少时候是二者混合的场景。

大魏仍是从实践角度举例。在京东买大魏的书100本,选完了下单支付,付钱,那么买书这件事用的就是同步模型。

图片

图片

图片

在上图的同步模型中,设计到的模块至少有:减小商品库存、创建订单、前台支付。


若是到支付页面,一看:须要这么多钱,犹豫了,暂时先不支付了。可能过了一个小时候想清楚了,才支付,那这就变成了异步事务。咱们在京东退出支付页面时,也会提示若是24个小时未支付的话(截图的时候,已通过了几分钟),订单会自动取消。

图片

若是咱们3个小时以后支付,确定也能支付成功。那这三个小时的时间里,事务是被保存在消息队列里了(MQ)。


因此说,分布式事务不少时候是同步和异步混合的场景。并且咱们在设计这种场景时,还须要保证业务的吞吐量和相应延迟。


因此说,分布式事务,有CP和AP两种常见模型。典型的CP如电商购物,强调一致性。典型的AP模型如发blog、发微信朋友圈。而AP和CP这两种模型,既有异步,又有同步的。


拷问5:分布式事务设计的核心要点是什么?

分布式事务设计的问题,自己是架构设计的问题。架构设计,分为:服务和数据两大块。不少时候,数据和服务是紧耦合的。所以须要进行拆分。


在微服务架构中,每一个微服务都有本身的DB,其实就是为了把分布式事务拆分红本地事务。


针对红帽coolstore的demo而言,咱们就是将长事务拆分红短事务,将短事务拆分红本地事务。


图片

这样,每一个本地事务都只操做本身的数据,也就是说DB/缓存/MQ必需要有事务管理能力(这个后面讲),本地事务才能实现。但每一个本地事务之间是有关联的。例如:A(下订单)->B(减库存)->C(发货)。若是A成功,B成功,C成功,那么整个分布式事务成功。

那么,若是C失败呢?

C会发生回滚,B、A会发生补偿。C不须要补偿,由于本地事务能够直接rollback。


咱们看一下MySQL如何实现事务管理(BEGIN ROLLBACKCOMMIT):


<?php$dbhost = 'localhost:3306';  // mysql服务器主机地址$dbuser = 'root';            // mysql用户名$dbpass = '123456';          // mysql用户名密码$conn = mysqli_connect($dbhost, $dbuser, $dbpass);if(! $conn ){die('链接失败: ' . mysqli_error($conn));}// 设置编码,防止中文乱码mysqli_query($conn, "set names utf8");mysqli_select_db( $conn, 'RUNOOB' );mysqli_query($conn, "SET AUTOCOMMIT=0"); // 设置为不自动提交,由于MYSQL默认当即执行mysqli_begin_transaction($conn);            // 开始事务定义
if(!mysqli_query($conn, "insert into runoob_transaction_test (id) values(8)")){    mysqli_query($conn, "ROLLBACK");     // 判断当执行失败时回滚}
if(!mysqli_query($conn, "insert into runoob_transaction_test (id) values(9)")){    mysqli_query($conn, "ROLLBACK");      // 判断执行失败时回滚}mysqli_commit($conn);            //执行事务mysqli_close($conn);?>

而Redis事务管理的基础是:MULTI 、 EXEC 、 DISCARD 和 WATCH。

关于Redis的事务管理,能够参照这篇文章:

https://cloud.tencent.com/developer/article/1798560


图片



拷问5:分布式事务框架不少,实际到底哪一种用的多。

谈到分布式事务的架构,有不少:XA、 TCC 、SAGA、 事务消息。咱们不谈概念,哪一种用的多呢?

实际应用中,同步主要用saga、异步主要使用事务消息。

saga就是事务补偿,这上文已经有所介绍。


MQ事务消息重点再也不是保证全部子事务的原子性,而是保证本地事务和发送MQ消息的原子性。相对于saga,MQ事务消息不用提供补偿接口)。


须要注意的是,不是全部的MQ都支持事务消息,目前只有RocketMQ支持。

如下内容节选自:https://juejin.cn/post/6844903951448408071


普通MQ的消息处理流程:

图片

  • 消息生成者发送消息

  • MQ收到消息,将消息进行持久化,在存储中新增一条记录

  • 返回ACK给生产者

  • MQ push 消息给对应的消费者,而后等待消费者返回ACK

  • 若是消息消费者在指定时间内成功返回ack,那么MQ认为消息消费成功,在存储中删除消息,即执行第6步;若是MQ在指定时间内没有收到ACK,则认为消息消费失败,会尝试从新push消息,重复执行四、五、6步骤

  • MQ删除消息


事务消息处理的流程

图片

  • 事务消息与普通消息的区别就在于消息生产环节,生产者首先预发送一条消息到MQ(这也被称为发送half消息)

  • MQ接受到消息后,先进行持久化,则存储中会新增一条状态为待发送的消息

  • 而后返回ACK给消息生产者,此时MQ不会触发消息推送事件

  • 生产者预发送消息成功后,执行本地事务

  • 执行本地事务,执行完成后,发送执行结果给MQ

  • MQ会根据结果删除或者更新消息状态为可发送

  • 若是消息状态更新为可发送,则MQ会push消息给消费者,后面消息的消费和普通消息是同样的


RocketMQ的模式有利于异步解耦。


咱们想象一个场景-秒杀系统。

如下内容节选自:https://www.jianshu.com/p/06e9a1d75bd5

图片

流程说明以下:

  1. 注册系统向消息队列 RocketMQ 发送半事务消息。
    1.1 半事务消息发送成功,进入 2。
    1.2 半事务消息发送失败,注册系统不进行注册,流程结束。(最终注册系统与邮件通知系统数据一致

  2. 注册系统开始注册。
    2.1 注册成功,进入 3.1。
    2.2 注册失败,进行 3.2。

  3. 注册系统向消息队列 RocketMQ 发送半消息状态。
    3.1 提交半事务消息,产生注册成功消息,进入 4。
    3.2 回滚半事务消息,未产生注册成功消息,流程结束。(最终注册系统与邮件通知系统数据一致)

  4. 邮件通知系统接收消息队列 RocketMQ 的注册成功消息。

  5. 邮件通知系统发送注册成功邮件。(最终注册系统与邮件通知系统数据一致)


总结:

  1. 分布式事务针对的对象是data,它能够在DB/缓存/ES/MQ中.

  2. CAP模型中,CP、AP较多。前者强调一致性,后者强调吞吐量。而AP和CP这两种模型,既有异步,又有同步的。

  3. 分布式事务设计的核心要点是:解耦拆分。将分布式事务拆成本地事务。

  4. 在分布式系统设计中:同步主要用saga、异步主要使用事务消息。事务消息不须要写补偿接口,所以代码侵入低。RocketMQ支持事务消息。

相关文章
相关标签/搜索