在当今的分布式系统中,数据的一致性和事务的处理成为了关键问题。随着应用程序的规模不断扩大和复杂性的增加,单一数据库事务的能力已经无法满足需求。因此,引入了分布式事务的概念,以确保跨多个节点的操作能够保持一致性。
题目
什么情况下需要使用分布式事务,有哪些方案?
更多面试题目请见
面试刷题小程序
推荐解析
是什么?
一般在跨多个数据库、或者不同服务的情况下需要用到分布式事务,比如订单服务和库存服务,下订单和扣库存属于不同服务的方法,因此本地事务无法保证一致性,需要引入分布式服务。
分布式事务是由多个本地事务组成的
,分布式事务跨越了多设备,之间又经历的复杂的网络,可想而知想要实现严格的事务道路阻且长。
我们就先来看看常见的分布式事务方案:2PC、3PC、TCC、本地消息、事务消息。
2PC
2PC,Two-phase commit protocol,即两阶段提交协议。它引入了一个事务协调者角色,来管理各个参与者(就是各数据库资源)。
整体分为两个阶段,分别是准备阶段和提交/回滚阶段。
我们先来看看第一个阶段,即准备阶段。
由事务协调者给每个参与者发送准备命令,每个参与者收到命令之后会执行相关事务操作,你可以认为除了事务的提交啥都做了。
然后每个参与者会返回响应告知协调者自己是否准备成功。
协调者收到每个参与者的响应之后就进入第二阶段
,根据收集的响应,如果有一个参与者响应准备失败那么就向所有参与者发送回滚命令,反之发送提交命令。
这个协议其实很符合正常的思维,就像我们大学上课点名的时候,其实老师就是协调者的角色,我们都是参与者。
老师一个一个的点名,我们一个一个的喊到,最后老师收到所有同学的到之后就开始了今天的讲课。
而和点名有所不同的是,
老师发现某几个学生不在还是能继续上课,而我们的事务可不允许这样
。
事务协调者在第一阶段未收到个别参与者的响应,则等待一定时间就会认为事务失败,会发送回滚命令,所以在 2PC 中事务协调者有超时机制。
我们再来分析一下 2PC 的优缺点。
2PC 的优点
是能利用数据库自身的功能进行本地事务的提交和回滚,也就是说提交和回滚实际操作不需要我们实现,不侵入业务逻辑由数据库完成,在之后讲解 TCC 之后相信大家对这点会有所体会。
2PC 主要有三大缺点
:同步阻塞、单点故障和数据不一致问题。
同步阻塞
可以看到在第一阶段执行了准备命令后,我们
每个本地资源都处于锁定状态
,因为除了事务的提交之外啥都做了。
所以这时候如果本地的其他请求要访问同一个资源,比如要修改商品表 id 等于 100 的那条数据,那么此时是被阻塞住的,必须等待前面事务的完结,收到提交/回滚命令执行完释放资源后,这个请求才能得以继续。
所以假设这个分布式事务涉及到很多参与者,然后有些参与者处理又特别复杂,特别慢,那么那些处理快的节点也得等着,所以说效率有点低。
单点故障
可以看到这个
单点就是协调者,如果协调者挂了整个事务就执行不下去了
。
如果协调者在发送准备命令前挂了还行,毕竟每个资源都还未执行命令,那么资源是没被锁定的。
可怕的是在发送完准备命令之后挂了,这时候每个本地资源都执行完处于锁定状态了,都杵着了,这就很僵硬了,如果是某个热点资源都阻塞了,这估计就要完蛋了。
数据不一致问题
因为协调者和参与者之间的交流是经过网络的,而网络有时候就会抽风的或者发生局部网络异常。
那么就有可能导致某些参与者无法收到协调者的请求,而某些收到了。比如是提交请求,然后那些收到命令的参与者就提交事务了,此时就产生了数据不一致的问题。
小结一下 2PC
至此我们来先小结一些 2PC ,它是一个同步阻塞的强一致性两阶段提交协议,分别是准备阶段和提交/回滚阶段。
2PC 的优势在于对业务没有侵入,可以利用数据库自身机制来进行事务的提交和回滚。
它的缺点:是一个同步阻塞协议,会导致高延迟和性能的下降,并且存在协调者单点故障问题,极端情况下会有数据不一致的问题。
当然这只是协议,具体的落地还是可以变通了
,比如协调者单点问题,我就搞个主从来实现协调者,对吧。
分布式数据库的 2PC 改进模型
可能有些人对分布式数据库不熟悉,没有关系,我们主要学的是思想,看看人家的思路。
我简单的讲下 Percolator 模型,
它是基于分布式存储系统 BigTable 建立的模型
,BigTable 是啥也不清楚的同学没有关系影响不大。
还是拿转账的例子来说,我现在有 200 块钱,你现在有 100 块钱,为了突出重点我也不按正常的结构来画这个表。
然后我要转 100 块给你。
此时事务管理器发起了准备请求,然后我账上的钱就少了,你账上的钱就多了,而且
事务管理器还记录下这次操作的日志
。
此时的数据还是私有版本,别的事务是读不到的,简单的理解 Lock 上有值就还是私有的。
可以看到我的记录 Lock 标记的是 PK,你的记录标记的是指向我的记录指针,这个 PK 是随机选择的。
然后事务管理器会向被选择作为 PK 的那条记录发起提交指令。
此时就会把我的记录的锁给抹去了,这等于我的记录不再是私有版本了,别的事务就都能访问了。
那你的记录上还有锁啊?不用更新吗?
嘿嘿不需要及时更新,因为访问你的这条记录的时候会去根据指针找我的那个记录,发现记录已经提交了所以你的记录就可以被访问了。
有人说这效率不就差了,每次都要去找一次,别急。
后台会有个线程来扫描,然后更新把锁记录给去了。
这不就稳了嘛。
相比于 2PC 的改进
首先 Percolator 在提交阶段不需要和所有的参与者交互,主需要和一个参与者打交道,所以这个提交是原子的!
解决了数据不一致问题
。
然后事务管理器会记录操作日志,这样当事务管理器挂了之后选举的新事务管理器就可以通过日志来得知当前的情况从而继续工作,
解决了单点故障问题
。
并且 Percolator 还会有后台线程,会扫描事务状况,在事务管理器宕机之后会回滚各个参与者上的事务。
可以看到相对于 2PC 还是做了很多改进的,也是巧妙的。
其实分布式数据库还有别的事务模型,不过我也不太熟悉,就不多哔哔了,有兴趣的同学可以自行了解。
还是挺能拓宽思想的。
其他补充
鱼聪明 AI 的回答:
鱼聪明 AI 地址:https://www.yucongming.com/
XA(eXtended Architecture)
XA
是一个由 X/Open 和 Open Group 提出的标准,用于在分布式事务环境中管理多个资源管理器(如数据库或消息队列)的事务性操作。XA 提供了一种协议,使得这些资源管理器能够参与到一个全局事务中,并保证事务的 ACID 特性(原子性、一致性、隔离性和持久性)。
主要特点和机制
:
-
两阶段提交(2PC)
:XA 协议的核心机制是两阶段提交。在两阶段提交中,事务协调者(Transaction Coordinator)协调多个参与者(Participants)的资源管理器,确保所有参与者要么都提交事务,要么都回滚事务,从而保证事务的一致性。
-
全局事务管理
:XA 提供了一个全局事务管理的框架,允许应用程序在多个不同的数据库或资源上执行操作,并以全局的方式进行事务管理。
适用场景
:
-
需要跨多个数据库或资源的事务操作,例如在订单和库存之间保持一致性。
-
优点
:
缺点
:
-
性能损耗较大,特别是在分布式环境下网络延迟较高时。
-
存在单点故障问题,事务协调者故障会导致整个系统的事务受影响。
TCC(Try-Confirm-Cancel)
TCC
是一种基于补偿事务的分布式事务解决方案,主要用于解决分布式系统中的数据一致性问题。TCC 的核心思想是将事务分解为三个阶段:尝试(Try)、确认(Confirm)和取消(Cancel),每个阶段对应一个操作。
主要特点和机制
:
-
三阶段处理
:TCC 事务通过 Try、Confirm 和 Cancel 三个阶段来实现:
-
-
-
Cancel
:取消操作,释放预留的资源,回滚事务。
-
补偿机制
:TCC 通过补偿操作来保证最终一致性,即使在部分参与者失败的情况下也可以进行处理。
适用场景
:
-
-
需要较大的灵活性和容错能力,例如电商交易系统中的订单操作和库存扣减。
-
业务逻辑相对复杂,不适合使用传统的两阶段提交协议。
优点
:
缺点
:
-
实现和维护成本较高,需要额外的补偿逻辑来保证最终一致性。
-
对业务代码有一定要求,需要开发者显式地定义 Try、Confirm 和 Cancel 三个操作。
区别和选择: