【面试】分布式事务方案与分布式系统一致性

分布式事务就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。就是一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败。本质上来说,分布式事务就是为了保证不同数据库的数据一致性。

分布式系统的经典基础理论   

CAP 理论

对于一个分布式计算系统来说,不可能同时满足以下三点:

  • 一致性(Consistence) :所有节点访问同一份最新的数据副本
  • 可用性(Availability):每次请求都能获取到非错的响应——但是不保证获取的数据为最新数据
  • 分区容错性(Partition tolerance) : 分布式系统在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务。

那么,上面的三点分别是什么玩意儿?为什么又只能同时满足两项呢?

我们先看这样一个场景,现在我们系统部署了两份(两个节点,web1 和 web2 ),同样的业务代码,但是维护的是自己这个节点生成的数据。但是用户访问进来,可能会访问到不同的节点。

但是不管是访问web1 还是web2 ,在用户参数数据 过后,这个数据都必须得同步到另外的节点,让用户不管访问哪个节点,都是响应他需要的数据。如下图:

分区容错性

就算上面这两个节点之间发生了网络故障,无法发生同步的问题,但是用户访问进来,不管到哪个节点,这个节点都得单独提供服务,这一点对于互联网公司来说,是必须要满足的。

当 web1 和 web2 之间的网络发生故障,导致数据无法进行同步。用户在web1 上写了数据,马上又访问进来读取数据,请求到了 web2,但是此时 web2 是没有数据的。那么我们是 给用户返回 null ?还是说给一些提示,说系统不可用,稍后重试呢?

都不妥吧,兄弟。

一致性

如果要保证可用性,那么有数据的节点返回数据,没数据的节点返回 null ,就会出现用户那里看到的是一会儿有数据,一会儿没有数据,此时就存在 一致性 的问题。

可用性

如果保证一致性,那么在用户访问的时候,不管 web1 还是web2 ,我们可能会返回一些提示信息,说系统不可用,稍后再试等等,保证每次都是一致的。明明我们有数据在,但是我们系统却响应的是提示信息,此时就是 可用性 的问题。

由于分区容错性(P)是必须保证的,那么我们分布式系统就更多是在一致性(CP) 和可用性(AP)上做平衡了,只能同时满足两个条件。

其实,大家想想,ZK 是不是就是严格实现了 CP ,而 Eureka 则是保证了 AP。

其实分布式事物强调的就是一致性。

 

几种分布式事物解决方案

2 PC

XA规范 描述了全局的事务管理器与局部的资源管理器之间的接口。XA规范的目的是允许多个资源(如数据库,应用服务器,消息队列,等等)在同一事务中访问,这样可以使ACID属性跨越应用程序而保持有效。

XA 使用 两阶段提交(2PC) 来保证所有资源同时提交或回滚任何特定的事务。

大家想一个场景,在做单应用的时候,有的同学连过两个库吧?在一个事物中会同时向两个系统插入数据。但是对于普通事物来讲,是管不了的。

看下图(只是举例这种操作的套路,不局限于下面的业务):

一个服务里面要去操作两个库,如何保证事物成功呢。

这里我们介绍一个框架 Atomikos ,他就是实现了这种 XA 的套路。看代码:

具体代码移步 Github AtomikosJTATest[1]: https://github.com/heyxyw/learn/blob/master/distributed-transaction/src/main/java/com/zhouq/jta/AtomikosJTATest.java[2]

看到上面的图了哇,Atomikos 自己实现了一个事物管理器。我们获取的连接都从它哪里拿。

  • 第一步先开启事务,然后进行预提交,db1 和 db2 都先进行预先执行,注意:这里没有提交事物
  • 第二步才是真正的提交事物,由 Atomikos 来发起提交的,如果出现异常则发起回滚操作。

这个过程是不是就有两个角色了,一个 事务管理器,一个资源管理器(我们这里是 数据库,也可以是其他的组件,消息队列什么的)。

整个执行过程是这样:

上图是正常情况,下图是一方出现故障的情况。

图片来自:XA 事务处理[3]:https://www.infoq.cn/article/xa-transactions-handle[4] ,具体关于XA 的详细讲解,可以好好看看。整个2PC 的流程:

第一阶段(提交请求阶段)

  1. 协调者节点向所有参与者节点询问是否可以执行提交操作,并开始等待各参与者节点的响应。
  2. 参与者节点执行询问发起为止的所有事务操作,并将Undo信息和Redo信息写入日志。
  3. 各参与者节点响应协调者节点发起的询问。如果参与者节点的事务操作实际执行成功,则它返回一个"同意"消息;如果参与者节点的事务操作实际执行失败,则它返回一个"中止"消息。

第二阶段 (提交执行阶段)

成功当协调者节点从所有参与者节点获得的相应消息都为"同意"时:

  1. 协调者节点向所有参与者节点发出"正式提交"的请求。
  2. 参与者节点正式完成操作,并释放在整个事务期间内占用的资源。
  3. 参与者节点向协调者节点发送"完成"消息。
  4. 协调者节点收到所有参与者节点反馈的"完成"消息后,完成事务。

失败如果任一参与者节点在第一阶段返回的响应消息为"终止",或者 协调者节点在第一阶段的询问超时之前无法获取所有参与者节点的响应消息时:

  1. 协调者节点向所有参与者节点发出"回滚操作"的请求。
  2. 参与者节点利用之前写入的Undo信息执行回滚,并释放在整个事务期间内占用的资源。
  3. 参与者节点向协调者节点发送"回滚完成"消息。
  4. 协调者节点收到所有参与者节点反馈的"回滚完成"消息后,取消事务。

有时候,第二阶段也被称作完成阶段,因为无论结果怎样,协调者都必须在此阶段结束当前事务。

 

基于可靠消息-消息服务中间件

我们以创建订单下单过程和 后面出库 的流程为例来讲述上面的图。

在下单逻辑里面(Producer 端),我们先生成一个订单的数据,比如订单号,数量等关键的信息,先包装成一条消息,并把消息的状态置为 init ,然后发送到 独立消息服务中,并且入库。

接下来继续处理 下单的其他本地的逻辑。

处理完成后,走到确认发送消息这一步,说明我的订单是能够下成功的。那么我们再向消息服务里面发送一条confirm 的消息,消息服务里面就可以把这个订单的消息状态修改为 send 并且,发送到消息队列里面。

接下来,消费者端去消费这条消息。处理自己这边的逻辑,处理完成以后,然后反馈消息处理结果到独立消息服务,独立消息服务把消息状态置为 end 状态 ,表示结束。但是得注意保证接口的幂等性,避免重复消费带来的问题。

这里面可能出现的问题,以及各个步骤怎么解决的:

1.比如在 prepare 阶段就发生异常,那么这里订单这块都不会下成功。但是我们说,我们这里是基于可靠消息,得保证我们的消息服务是正常的。

2.在 comfirm 出现异常,此时发送确认失败,但是我们的单已经下成功了。这种情况,我们就可以在独立消息服务中起一个定时任务,定时去查询 消息状态为 init 的数据,去反向查询 订单系统中的单号是否存在,如果存在,那么我们就把消息置为 send 状态,然后发送到 消息队列里面,如果查询到不存在的订单,那么就直接抛弃掉这条消息。所以这里我们的订单系统得提供批量查询订单的接口,还有下游的消费系统得保证幂等。保证重复消费的一致性。

3.消息队列丢消息或者下游系统一直处理失败,导致没有消息反馈过来,出现一直是 send 状态的消息。此时独立消息我们还需要一个定时任务,就是处理这种 send 状态的消息,我们可以进行重发,直到后面系统消费成功为止。

4.最后消费者这端,我们在消费的时候,如果出现消费异常,或者是系统bug 导致异常的情况。那么这里我们还可以去记录日志,如果不是系统代码问题,是网络抖动导致的,那么在上面第三种情况,消息系统会重新发送消息,我们再处理就是。如果是一直失败,你就要考虑是不是你的代码真的有问题,有bug 了吧。

5.最后的保底方案,记录日志,出现问题人肉处理数据。现在我们系统出现错误,以目前的技术手段是没办法做到都靠机器去解决的,都得靠我们人。据我了解,现在很多大厂都会有这样的人,专门处理这种类型的问题,手动去修改数据库的方式。我们之前待的小厂,基本上都是靠我们自己去写 sql 去修改数据的,想想,是不是?

 

贴一下关键的独立消息服务核心逻辑代码框架

定时任务

 

TCC 方案

 

转发 一文搞懂面试必备的分布式事物方案

视频

链接:https://pan.baidu.com/s/1uLILp5sEthizjv0cbf6hKg 
提取码:n2xk 
 

深入理解分布式事务 http://www.codeceo.com/article/distributed-transaction.html

分布式事务?No, 最终一致性  https://zhuanlan.zhihu.com/p/25933039

聊聊分布式事务,再说说解决方案    https://www.cnblogs.com/savorboard/p/distributed-system-transaction-consistency.html

分布式系统一致性    分布式服务化系统一致性的“最佳实干”

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值