分布式事务(一):概念介绍与刚性事务

引言

Hi,我是东东拿铁,好久没写技术文了。

上一次面试被问到分布式事务,还是在上一次,那时候关于分布式事务的问题很低频,一问一个不吱声。

那时候哪用过分布式事务啊,准备高并发、高性能、高可用这方面的知识就已经让人精疲力竭了。

近几年工作接触的依然是高并发、高性能比较多,因此对数据一致性方面的了解仍然不足,既然没能做到游刃有余,还是面试高频题,那不如趁着这个机会重新学习一下。

我会在接下来几篇文章详细介绍分布式事务,包括基础知识、技术方案、Seata、方案对比。

如果你也对分布式事务已经遗忘,或者根本没有了解,点个关注,第一时间获得后续更新。

如果你不想看技术文章,欢迎你看看我的别的文章换个心情,传送门:程序员提高职业上限的简单心法

事务

讲分布式事务前,我们先简单聊聊什么是事务。

事务是一个逻辑工作单元,它包含了一组数据库操作(新增、更新、删除等),这些操作要么全部成功执行,要么全部不执行,以确保数据的一致性和完整性。

事务有以下四个特性:

  1. 原子性(Atomicity):事务中的所有操作要么全部成功,要么全部失败。例如,在一个银行账户系统中,从一个账户向另一个账户转账,如果转账过程中出现问题,那么整个转账操作会被回滚,确保两个账户的状态不会出现部分更新的情况。

  2. 一致性(Consistency):事务执行前后,数据库的状态必须是一致的。这意味着数据库中的数据必须满足所有的完整性约束,如主键约束、外键约束等。例如,在一个订单系统中,创建订单时,必须确保库存数量足够,如果库存不足,事务会回滚,以保证数据的一致性。

  3. 隔离性(Isolation):多个事务并发执行时,它们之间的操作相互隔离,互不干扰。数据库通常通过不同的隔离级别来实现隔离性,例如读未提交、读已提交、可重复读和串行化。不同的隔离级别在性能和数据一致性之间进行权衡。

  4. 持久性(Durability):一旦事务提交,其结果必须是持久的,即使系统出现故障也不能丢失。数据库通常通过将数据写入磁盘或其他持久存储介质来实现持久性。

传统互联网一般使用的是单体服务,在多个数据库操作时,直接使用本地事务即可。本地事务是指在单个数据库连接或单个系统内部进行的事务处理,本地事务使用非常简单,如果使用Spring框架,只需要在方法上加上@Transactional 注解即可。

以网上购物为例,当你在一个电商平台上购买商品时,系统需要进行一系列的操作,包括更新商品库存、记录订单信息、从你的支付账户中扣款等。这些操作都在同一个数据库系统中进行,并且被包含在一个本地事务中。

如果在这个过程中一切顺利,所有的操作都会成功执行,商品库存减少,订单被记录下来,你的支付账户余额也会相应减少。但是如果在任何一个环节出现问题,比如库存不足、支付失败等,整个事务就会回滚。这意味着之前已经执行的操作(如减少库存、记录订单等)都会被撤销,就好像整个购物过程从未发生过一样,保证了数据的一致性和完整性。

而现在的互联网公司大都采用微服务架构,商品、订单等不同的业务系统有自己独立的数据库,而本地事务只支持单一数据库的回滚操作。

那么不同数据库间,如何保证数据一致性呢?为了解决这个问题,就要说我们的主题:分布式事务

从CAP 定理谈起

既然分布式事务的背景是分布式事务,那么我们先从CAP定理谈起。

在一个分布式系统中,最多只能在一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)中三者满足其二,不能同时满足这三项。

C(Consistency)一致性:可以想象成你和你的朋友一起看一本共享的在线账本。一致性就是说,当你在账本上记录了一笔收入,你的朋友在同一时间去看这个账本时,也能看到这笔收入被正确地记录了,账本上的数据是一致的,不会出现你看到有这笔收入而你的朋友却看不到的情况。

A(Availability)可用性:就好比这个在线账本随时都能被你和你的朋友打开查看或者进行记录操作,不会出现打不开账本或者无法进行记录的情况,系统总是能够及时响应请求。

P(Partition tolerance)分区容错性:可以理解为即使网络出现了问题,把系统分成了几个不能互相通信的部分(就像两个城市之间的道路断了),系统也能继续正常运行。

在一个分布式系统中,最多只能同时满足一致性、可用性和分区容错性这三个特性中的两个。这是因为在面对网络分区的情况下,要保证一致性就可能需要牺牲可用性(比如停止服务来同步数据,确保所有节点的数据一致);而要保证可用性,就可能无法保证强一致性(因为不同节点的数据可能无法及时同步)。

例如,在一个分布式存储系统中,如果选择了强一致性和分区容错性(CP),那么在网络分区发生时,可能会为了保证数据的一致性而暂停部分节点的服务,导致系统的可用性降低。如果选择了可用性和分区容错性(AP),那么在网络分区时,不同节点上的数据可能会出现不一致的情况。

为什么没有CA,因为我们是分布式系统,一定存在分区P

分布式事务

分布式事务是指在分布式系统中,涉及多个节点或服务的事务操作。在传统的单体应用中,事务通常由单个数据库管理系统来控制,保证了操作的原子性、一致性、隔离性和持久性(ACID)。然而,在分布式环境下,由于数据和操作可能分布在不同的节点、数据库或服务上,实现事务的一致性变得更加复杂。

分布式事务的依然要满足事务的四个特性,原子性、一致性、隔离性、持久性,只不过特性的适用范围是系统的多个节点。

分布式事务又分为刚性事务和柔性事务两种,我们先说刚性事务。

2PC(两阶段提交)

刚性事务又分成2PC和3PC两种方案, 我们先说说2PC。

2PC就是将事务进行两阶段提交,第一个阶段为事务预提交阶段,第二个阶段为事务提交或回滚阶段,由事务协调者(Coordinator)对所有的事务参与者进行整体协调把控。

第一步(Prepare):Coordinator 向各个分布式事务的参与者下达了 Prepare 指令,各个事务分别将 SQL 语句在数据库执行但不提交,并且将就绪状态上报给 Coordinator。

第二步(Commit/Rollback):如果所有节点都已就绪,那么 Coordinator 就下达Commit 指令,各个参与者提交本地事务;如果有任何一个节点不能就绪,Coordinator则下达 Rollback 指令进行本地回滚。

2PC的具体实现,实际应用就不得不提到XA协议了,XA 协议是 X/Open 组织提出的一种分布式事务处理规范,大多数银行系统和很老的系统使用的就是XA协议下的分布式解决方案。

这套方案依赖于底层数据库的支持,DB 这层首先得要实现 XA 协议,比如常见的 Oracle XA 和 MySQL InnoDB,都是支持 XA 协议的。

很多人没有听过XA,主要是因为现在的互联网公司早就不采用XA这套协议了,是因为XA协议有一个致命的缺点:不支持高并发。

为什么?因为在事务的Prepare阶段,我们必须持续占用一个数据库连接资源,这个资源直到事务协调者告诉我们提交时,这个资源才会释放。而数据库的连接池又是特别宝贵的资源。设想A服务已经进入Prepare阶段,而B服务因为某些原因迟迟没有上报Prepare状态,那么A的资源就会持续占用。

极端情况下,当连接池打满,所有和数据库的操作都会进入等待连接状态,直到超时。

而互联网的场景就是高并发,因为并发量特别高,所以每个事务必须尽快释放掉所持有的数据库连接资源。事务执行时间越短越好,这样才能让别的事务尽快被执行。

其实,2PC方案主要有3个缺点

  1. 单点问题,一旦事务协调者出现故障,所有事务参与者无法接收到Commit或者Rollback,资源占用。

  2. 数据一致性问题,当局部网络出现异常,可能会有部分服务无法收到Commit或者Rollback,那么全局数据就不一致了。

  3. 也就是我们刚刚说的性能问题。

3PC(三阶段提交)

既然有以上问题,3PC方案应运而生,针对2PC的缺点,3PC主要做了以下改进

  1. 事务参与者也具备超时机制,在2PC方案中,只有事务协调者才有超时控制,那么事务参与者可以自己根据超市时间,对事务进行提交、回滚

  2. 3PC方案在2PC的Prepare(准备阶段),再次进行拆分,拆分成了CanCommit(事务询问)和事务预提交(PreCommit)阶段。

我们重点说一下第二点,CanCommit和PreCommit,还记得上面2PC方案中,A事务已经进入,而B事务所需的资源可能被占用,导致A一直等待的情况吗。

CanCommit就是提前询问B,是否能够进入准备状态。假设不能准备状态,直接返回,那么A事务也可以提前释放,不需要等着B了。

似乎2PC所有的资源占用问题,得到了很大的改善,但是事情并没有这么简单。

事务的参与者具备了超时机制,那么在超时情况下,事务自动提交。提交事务这个动作,并不是由事务协调者(Coordinator)发起的。

那么可以预见的,还是会出现数据一致性问题。

说在最后

本文从事务的特性开始,介绍了普通事务,以及分布式事务中刚性事务方案:2PC、3PC,并介绍了方案的实现原理与缺点。

可是2PC、3PC依然有缺点存在,似乎无法解决微服务架构下的分布式事务要求高性能的问题。

那有什么更好的方案吗?下一篇我会介绍分布式事务框架Seata框架是如何解决我们最关注的资源性能问题的,也是现在绝大部分公司最常用的解决方案。

点击关注,也希望你点赞、评论、收藏,这对我来说真的很重要。也欢迎你加我的wx:Ldhrlhy10,一起交流~

本篇文章是第59篇原创文章,2024目标进度59/100,欢迎围观。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值