很多人估计会说,我在项目中完全没有涉及到过分布式事务,而面试官老喜欢问,真TM烦!
本文就来聊聊分布式事务,有哪些方案和实现。文章有点长,可以先收藏,有时间了慢慢看。
什么是事务?举个生活中的例子:你去小卖铺买东西,"一手交钱,一手交货"就是一个事务的例子,交钱和交货要么都成功,要么都失败。
其实嘛,分布式事务从实质上看与数据库事务的概念是一致的,既然是事务也就需要满足事务的基本特性(ACID),只是分布式事务相对于本地事务而言其表现形式有很大的不同。
本地事务的时代,如果需要同时操作数据库的多条记录,而这些操作可以放到一个事务中,那么我们可以通过数据库提供的事务机制就可以实现。要么全部成功,要么全部失败。比如我们Spring项目中,处理本地事务只需要一个注解 @Transactional 就能解决,但需要注意事务失效场景,不然就算你使用了这个注解事务照样没有。
而分布式事务是为了解决微服务架构中不同节点之间的数据一致性问题。这个一致性问题本质上解决的也是传统事务需要解决的问题,即一个请求在多个微服务调用链中,所有服务的数据处理要么全部成功,要么全部回滚。
你可以理解为分布式事务是多个本地事务组成,前面我们说了本地事务使用注解 @Transactional 就能解决,而多个本地事务,如果你还采用这个注解,那就无法解决了。
想解决问题,那就先想办法,把理论给想出来,至于如何实现,那就可能会有很多种方式了。
文章概览
在我的充电桩项目中,使用过三种方案的落地:
Atomikos:Spring Boot+MyBatis+Atomikos+MySQL(附源码)
Seata:实战分布式事务【Seata+Spring Cloud】
消息队列:
解决方案
常规的解决方案有三种类型:
基于XA协议的解决方案(基于DB来实现)
基于补偿的解决方案(业务层实现)
基于最终一致性的解决方案
下面再来看看每个类型有哪些具体方案;
1、基于XA协议的解决方案
2PC:2PC(两阶段提交协议)是分布式事务解决方案中的一种 。其基本思想是将事务的处理过程划分为两个阶段:准备阶段和提交阶段。
在准备阶段,协调者会询问所有参与者是否可以执行事务,并等待各参与者的回复。如果所有参与者都表示可以执行,则进入提交阶段。在提交阶段,协调者会告诉所有参与者执行事务并等待反馈。如果所有参与者都成功执行了事务,则整个事务被视为成功。
关于2PC的优缺点如下:
优点:
可靠性高:由于在提交阶段之前需要所有参与者的确认,因此可以确保只有当所有参与者都同意时,事务才会被提交,这提高了系统的可靠性。
适用性强:2PC适用于许多场景,特别是对于那些需要确保数据一致性的场景。
缺点:
阻塞问题:在准备阶段和提交阶段中,如果任何一个参与者出现故障或响应超时,整个事务就会陷入阻塞状态,导致系统性能下降。
单点故障:如果协调者出现故障或单点瓶颈,整个系统可能会受到影响。
效率问题:由于需要多次网络通信和等待反馈,因此相对于其他分布式事务解决方案,2PC的效率可能较低。
总的来说,虽然2PC具有高可靠性的优点,但在实际应用中需要考虑其阻塞、单点故障和效率等问题。因此,在选择分布式事务解决方案时,需要根据具体的应用场景和需求进行权衡和选择。
这里我们可以看到2PC尽管能实现分布式事务,但是存在的问题还是挺多的,所以,进一步引入了3PC
3PC:3PC(三阶段提交协议)是分布式事务解决方案中的一种。其核心思想是将事务处理过程分为三个阶段:准备阶段、预提交阶段和提交阶段。
在准备阶段,协调者询问所有参与者是否可以执行事务,并等待各参与者的回复。在预提交阶段,协调者根据各参与者的反馈来决定是否进行下一步的提交或回滚操作。而在提交阶段,根据之前的信息判断可以执行事务,协调者通知所有参与者提交事务或执行回滚。
优点:
减少了阻塞时间 :通过在预提交阶段收集更多的信息,3PC可以在不真正执行事务的情况下减少阻塞时间。
**提高了效率 **:在准备阶段,如果发现存在无法执行事务的参与者,则协调者可以决定终止整个事务的提交过程,这样能够更早地发现问题并作出决策,从而提高整体效率。
缺点:
复杂性增加 :相比两阶段提交协议(2PC),3PC引入了更多的阶段和交互过程,增加了系统的复杂性和实现的难度。
单点故障风险 :尽管3PC试图通过更多的阶段和反馈来提高系统的可靠性,但仍然存在单点故障的风险,特别是协调者的故障可能会对整个系统造成影响。
总体而言,3PC是一种改进的分布式事务解决方案,旨在解决2PC中可能存在的阻塞和效率问题。然而,它也增加了系统的复杂性和单点故障的风险。在选择使用哪种协议时,需要根据具体的应用场景和需求进行权衡和选择。
在XA协议解决方案中还有一种叫做JTA的解决方案。
JTA(Java Transaction API)是Java平台中用于分布式事务的规范。 它提供了一种标准的编程接口,用于在多个资源管理器(如数据库、消息队列等)之间协调事务。
JTA的主要优点包括:
跨平台性 :JTA是一个标准化的API,可以在不同的Java平台上使用,从而使得开发者能够轻松地实现分布式事务的跨平台一致性。
灵活性 :JTA支持多种资源管理器的集成,可以与不同的数据库、消息队列等系统进行交互,提供灵活的事务管理方式。
协调性强 :JTA可以确保事务的原子性、一致性、隔离性和持久性(ACID属性),在多个资源之间进行协调和同步,确保数据的一致性。
然而,JTA也存在一些缺点和挑战:
性能问题 :由于需要协调多个资源管理器之间的交互,JTA可能会引入一定的性能开销。特别是在高并发和大规模的分布式系统中,这种开销可能会更加明显。
复杂性 :JTA的实现需要处理多个资源管理器的交互和协调,对于开发者来说需要一定的学习和理解成本。此外,JTA的配置和管理也可能相对复杂。
依赖于特定的中间件或容器 :JTA通常需要依赖于特定的中间件或容器来支持其运行和协调事务。这可能会增加系统的复杂性和部署的难度。
综上所述,JTA作为一种分布式事务解决方案,在Java平台中得到了广泛应用,但它也面临性能、复杂性和依赖性问题等挑战。在使用JTA时,需要根据具体的应用场景和需求进行权衡和选择。
除了JTA,还有一种叫做JTS。
JTS(Java Transaction Service)是Java平台中用于分布式事务的另一个重要规范。JTS提供了一种标准的框架和API,用于在多个资源管理器之间协调和管理事务。
JTS的优点包括:
跨平台性 :JTS是一个标准化的规范,可以在不同的Java应用服务器和中间件之间进行事务协调,因此具有很好的跨平台性。
灵活性 :JTS支持多种资源管理器的集成,可以与各种数据库、消息队列、文件系统等交互,提供灵活的事务管理方式。
事务协调 :JTS能够协调多个资源之间的事务,确保事务的原子性和一致性。它提供了一套标准的接口和协议,使得不同的事务参与者可以相互通信和协调。
然而,JTS也存在一些缺点和挑战:
复杂性 :JTS的实现需要处理多个资源管理器之间的交互和协调,对于开发者来说需要一定的学习和理解成本。此外,JTS的配置和管理也可能相对复杂。
性能开销 :由于JTS需要协调多个资源之间的交互,可能会引入一定的性能开销。在高并发和大规模的分布式系统中,这种开销可能会更加明显。
依赖性问题 :JTS的实现通常需要依赖于特定的中间件或应用服务器,这可能会增加系统的复杂性和部署的难度。
总的来说,JTS是一种用于协调和管理分布式事务的Java规范,它提供了跨平台、灵活和事务协调的能力。然而,在使用JTS时也需要考虑其复杂性、性能开销和依赖性问题等挑战。在选择使用JTS或其他分布式事务解决方案时,需要根据具体的应用场景和需求进行权衡和选择。
好了,上面是常见的XA协议解决方案。
2、基于补偿的解决方案
典型两种解决方案:TCC和SAGA
TCC(Try-Confirm-Cancel)是一种分布式事务解决方案。其基本思想是将一个全局事务的流程分为Try
、Confirm
和Cancel
三个阶段。
TCC的优点:
简单高效 :相比于其他分布式事务解决方案,TCC的设计较为简单,可以有效地提高系统的吞吐量和性能。
灵活性高:在Try阶段,业务方可以尽可能地预检事务的可行性,从而在Confirm或Cancel阶段做出正确的决策。这种灵活性使得TCC可以适应不同的业务场景和需求。
可靠性高:通过Try、Confirm和Cancel三个阶段的协调,TCC可以确保事务的原子性和一致性,从而提高系统的可靠性。
然而,TCC也存在一些缺点和挑战:
业务侵入性:TCC需要在业务代码中显式地编写Try、Confirm和Cancel的逻辑,这可能会增加业务的复杂性并可能存在侵入性问题。
可靠性依赖:如果系统的可靠性完全依赖于Try、Confirm和Cancel这三个阶段的正确执行,那么系统的可靠性可能会受到挑战。一旦任何一个阶段出现错误或延迟,都可能导致整个事务的失败或不一致性。
协调成本:在分布式系统中,需要协调多个资源管理器(如数据库、消息队列等)来执行TCC事务,这可能会带来一定的协调成本。
总体来说,TCC是一种适用于多种场景的分布式事务解决方案,但在使用时需要注意业务侵入性、可靠性和协调成本等问题。在选择使用TCC或其他分布式事务解决方案时,需要根据具体的应用场景和需求进行权衡和选择。
SAGA是一种用于处理分布式事务的解决方案。它是一种基于协调者-参与者模式的分布式事务解决方案,主要适用于长事务场景。
SAGA的优点:
灵活性高:SAGA可以灵活地处理复杂的分布式事务,支持多种业务场景和需求。
可靠性高:SAGA通过协调多个参与者来完成一个全局事务,确保了事务的原子性和一致性。
方便易用:相比于其他分布式事务解决方案,SAGA更容易实现和使用,具有较高的可用性。
然而,SAGA也存在一些缺点和挑战:
性能开销:由于SAGA需要协调多个参与者来完成一个全局事务,可能会引入一定的性能开销。特别是在高并发和大规模的分布式系统中,这种开销可能会更加明显。
复杂性:SAGA的实现需要处理多个参与者之间的协调和交互,对于开发者来说需要一定的学习和理解成本。此外,SAGA的配置和管理也可能相对复杂。
回滚成本:在SAGA中,如果某个参与者执行失败需要回滚整个事务时,可能会导致较大的回滚成本。特别是在涉及多个资源和操作的复杂事务中,回滚成本可能会很高。
总的来说,SAGA是一种适用于处理复杂分布式事务的解决方案,具有灵活性和可靠性的优点。然而,在使用SAGA时也需要注意性能开销、复杂性和回滚成本等问题。在选择使用SAGA或其他分布式事务解决方案时,需要根据具体的应用场景和需求进行权衡和选择。
3、基于最终一致性的解决方案
常见的有三种:消息表、消息队列以及最大努力通知。
消息表方案是一种分布式事务解决方案,它主要用于解决跨系统间的数据一致性问题。以下是该方案的基本实现方式及其优缺点:
实现方式:
定义消息表:在系统中引入一个消息表,用于记录待处理或已处理的事务消息。
业务处理:当业务系统进行交易时,相关的数据更新会先在业务系统中完成,并将对应的事务消息记录在消息表中。
异步处理:通过消息队列或其他机制,异步地通知另一个系统去消费这些消息,并对相关联的外部系统或数据库进行操作,保证数据的最终一致性。
优点:
解耦:通过消息表,可以将不同系统的业务逻辑进行解耦,降低系统的复杂性。
灵活性:消息表方案可以灵活地处理各种复杂的业务场景和需求。
最终一致性:通过异步处理,可以保证数据的最终一致性,减少系统间的耦合和依赖。
缺点:
性能开销:由于需要异步处理和记录消息表中的消息,可能会对系统性能产生一定的影响。特别是在高并发的情况下,这种开销可能会更加明显。
数据同步延迟:由于异步处理的特性,可能会出现数据同步的延迟,导致在某些情况下数据的实时性无法得到保证。
一致性风险:如果消息表或异步处理的机制出现故障或错误,可能会导致数据的不一致。这需要额外的机制来保证数据的一致性。
技术复杂度:实现消息表方案需要一定的技术储备和经验,对于开发者来说可能存在一定的学习和理解成本。
总的来说,消息表方案是一种有效的分布式事务解决方案,它通过解耦、异步处理等方式来保证数据的一致性。然而,在使用该方案时也需要注意性能开销、数据同步延迟、一致性风险和技术复杂度等问题。在选择使用该方案时,需要根据具体的应用场景和需求进行权衡和选择。
消息队列方案是一种分布式事务解决方案,它通过使用消息队列来协调不同系统或服务之间的事务处理。
以下是该方案的基本实现方式及其优缺点:
实现方式:
消息生产与消费:在业务系统中,当需要执行分布式事务时,会产生消息并将其发送到消息队列中。这些消息可以表示一个操作或一系列操作。
异步处理:接收消息的系统或服务(消费者)异步地处理这些消息,执行相应的业务逻辑。
事务协调:通过消息队列的机制,可以协调不同系统或服务之间的事务处理,确保数据的一致性。
优点:
解耦:消息队列可以将不同系统或服务之间的业务逻辑进行解耦,降低系统的复杂性。
异步处理:通过异步处理机制,可以提高系统的响应速度和吞吐量。
灵活性:消息队列方案可以灵活地处理各种复杂的业务场景和需求。
可扩展性:消息队列方案具有良好的可扩展性,可以轻松地添加或删除消费者节点,实现负载均衡和高可用性。
缺点:
数据一致性风险:虽然消息队列可以协调不同系统或服务之间的事务处理,但仍存在数据不一致的风险。需要额外的机制来保证数据的一致性。
性能开销:消息队列的引入可能会增加系统的复杂性和性能开销。特别是在高并发和大规模的场景下,需要关注消息队列的性能和扩展性。
消息丢失与重复:在网络传输或系统故障等情况下,可能会出现消息的丢失或重复消费的问题,需要相应的机制来处理这些问题。
耦合性:虽然消息队列可以实现系统之间的解耦,但在实际使用中仍然需要注意不同系统之间的耦合性问题。过度的依赖或不当的使用可能导致系统之间的紧密耦合。
总的来说,消息队列方案是一种有效的分布式事务解决方案,它通过异步处理和协调不同系统或服务之间的事务来提高系统的性能和灵活性。然而,在使用该方案时也需要注意数据一致性风险、性能开销、消息丢失与重复以及耦合性等问题。在选择使用该方案时,需要根据具体的应用场景和需求进行权衡和选择。
最大努力通知方案(Best Effort Notification Scheme) 是一种分布式事务解决方案中的通知机制。它是一种较为宽松的保证机制,旨在以最大的努力去通知相关系统或服务进行相应的操作或更新,但不保证每次通知都能成功到达或被处理。
最大努力通知方案的特点和优势包括:
轻量级:该方案不需要复杂的协调和同步机制,实现相对简单轻量。
异步处理:采用异步处理的方式,可以减少系统间的耦合和等待时间,提高系统的响应速度。
保证部分一致性:尽管不保证每次通知都能成功,但尽可能地以最大的努力去通知相关系统或服务,从而保证部分数据的一致性。
灵活性:该方案可以根据实际需求进行灵活配置和调整,适应不同的业务场景和需求。
可扩展性:可以轻松地添加或删除通知的接收方,实现系统的扩展和升级。
最大努力通知方案的工作原理是,当需要进行分布式事务处理时,发送方将通知消息发送给接收方,但并不保证接收方一定能成功接收到或处理该消息。发送方在发送消息后,会记录发送的日志或状态,以便后续进行补偿操作或重试机制。如果接收方在一定的时间内没有响应或处理失败,发送方可以根据预定的策略进行重试、补偿或其他操作。
使用最大努力通知方案时需要注意的问题包括:
数据一致性风险:由于不保证每次通知都能成功到达或被处理,可能会存在数据不一致的风险。需要结合其他机制来保证数据的一致性。
消息丢失与重复:在网络传输或系统故障等情况下,可能会出现消息的丢失或重复发送的问题。需要相应的机制来处理这些问题,如消息重试、消息持久化等。
通知成功与否的确认:需要建立一种机制来确认通知是否成功到达并被处理,以便进行后续的操作或补偿。
总之,最大努力通知方案是一种相对简单的分布式事务解决方案中的通知机制,它以最大的努力去通知相关系统或服务进行操作或更新,但不保证每次都能成功。在实际应用中,需要根据具体的需求和场景来选择合适的解决方案。
很多人会吹牛,会讲大道理,但是一旦让他去做,可能就不知道如何下手了。
所以,前面说了这么多理论,下面我们来看看具体实现方案。
中间件
关于分布式事务相关问题,不是现在才有,都已经很多年了,所以,市面上也出现了很多关于分布式事务实现的中间件。
Atomiks
这个中间件,很多人估计没接触过,我之前在一篇文章里分享过(有代码实现):
Atomikos是一种中间件解决方案,用于支持分布式事务处理。它能够帮助处理跨多个数据库或系统的复杂事务,确保数据的一致性和完整性。
Atomikos中间件的主要特点包括:
支持多种数据源:Atomikos支持多种关系型数据库,如Oracle、MySQL、SQL Server等,可以方便地集成到不同的系统中。
事务管理:Atomikos提供了强大的事务管理功能,可以协调多个数据库或系统的操作,确保事务的原子性和一致性。
透明性:使用Atomikos,开发者可以以透明的方式处理分布式事务,无需在代码中显式地处理事务的协调和同步。
高可用性和可靠性:Atomikos中间件提供了高可用性和可靠性保障,通过支持集群部署和故障恢复机制,确保系统的稳定性和数据的可靠性。
易于集成:Atomikos提供了丰富的API和工具,方便与其他系统和应用进行集成。
使用Atomikos中间件可以带来以下优势:
简化开发:开发者无需关心分布式事务的复杂协调和同步问题,可以专注于业务逻辑的开发。
提高性能:通过异步处理和并发控制等技术手段,Atomikos可以提高系统的性能和响应速度。
保证数据一致性:通过协调多个数据库或系统的操作,Atomikos可以确保数据的一致性和完整性。
灵活扩展:Atomikos具有良好的可扩展性,可以轻松地添加或删除节点,实现负载均衡和高可用性。
然而,使用Atomikos中间件也需要注意一些问题,如性能开销、配置复杂性以及与其他中间件或系统的兼容性等。因此,在选择使用Atomikos或其他分布式事务解决方案时,需要根据具体的应用场景和需求进行权衡和选择。
Seata
Seata应该算是目前国内最火的,你了解分布式锁中间件,基本上都会去了解的中间件。
Seata是一种开源的分布式事务解决方案中间件。它主要用于解决微服务架构下的分布式事务问题,确保数据在多个服务或系统之间的一致性。
Seata中间件的主要特点和优势包括:
分布式事务管理:Seata能够协调并管理分布式事务,确保在多个数据库或系统之间的操作具备原子性和一致性。
高度集成性:Seata支持多种数据库和消息队列等中间件,可以方便地集成到不同的系统中。
透明性:Seata提供了透明化的分布式事务处理能力,开发者无需关心复杂的分布式事务协调和同步问题。
性能优化:Seata通过异步处理、并发控制等技术手段,提高系统的性能和响应速度。
易于使用:Seata提供了丰富的API和工具,简化了分布式事务的使用和开发过程。
高可用性和可靠性:Seata支持集群部署和故障恢复机制,确保系统的稳定性和数据的可靠性。
Seata中间件的工作原理主要是通过使用分布式事务协调器来协调多个数据库或系统的操作。在分布式事务处理过程中,Seata负责管理事务的全局状态,并确保所有参与者的操作都按照预期执行。如果发生任何问题或错误,Seata可以回滚整个事务,保证数据的一致性。
使用Seata中间件可以带来以下优势:
简化开发:开发者无需关心复杂的分布式事务协调和同步问题,可以更专注于业务逻辑的开发。
提高性能:Seata通过异步处理和并发控制等技术手段,可以提高系统的性能和响应速度。
保证数据一致性:Seata能够确保在多个系统或数据库之间的操作保持数据的一致性。
灵活扩展:Seata具有良好的可扩展性,可以轻松地添加或删除节点,实现负载均衡和高可用性。
总之,Seata是一种功能强大的分布式事务解决方案中间件,能够帮助开发者解决微服务架构下的分布式事务问题,确保数据的一致性和系统的稳定性。
TX-LCN
TX-LCN(Transactional Lightweight Containers Network)是一种分布式事务解决方案的中间件。它是一种轻量级的分布式事务框架,用于解决微服务架构下不同服务之间的数据一致性问题。
TX-LCN中间件的主要特点和优势包括:
轻量级设计:TX-LCN设计为轻量级框架,可以轻松集成到现有的微服务架构中,不增加系统复杂性和性能负担。
分布式事务协调:TX-LCN能够协调和管理分布式事务,确保多个服务或数据库之间的操作具有原子性和一致性。
柔性适配:该中间件支持多种数据库和消息队列等中间件,可以灵活地适配不同的技术栈和系统架构。
透明性:TX-LCN提供了透明化的分布式事务处理能力,开发者无需关心复杂的分布式事务协调和同步问题。
快速部署:由于该中间件提供了丰富的工具和配置选项,使得部署和配置变得更加简单快捷。
TX-LCN中间件的工作原理是基于分布式事务的协调和通信机制。它通过引入一个全局的事务协调器来协调多个服务或数据库的操作,确保在事务中的所有操作都按照预期执行。如果发生任何问题或错误,该中间件能够回滚整个事务,保证数据的一致性。
使用TX-LCN中间件可以带来以下优势:
简化开发:开发者无需关心复杂的分布式事务协调和同步问题,可以更专注于业务逻辑的开发。
提高性能:通过异步处理和并发控制等技术手段,可以提高系统的性能和响应速度。
保证数据一致性:TX-LCN能够确保在多个服务或数据库之间的操作保持数据的一致性,减少数据冲突和错误的可能性。
灵活扩展:该中间件具有良好的可扩展性,可以轻松地添加或删除节点,实现负载均衡和高可用性。
总之,TX-LCN是一种功能强大的分布式事务解决方案中间件,可以帮助开发者在微服务架构下解决分布式事务问题,确保数据的一致性和系统的稳定性。
总结
很多人很怕面试官问到分布式事务问题,尤其是问:你项目中有解决过分布式事务问题吗?怎么解决的?
如果项目中有分布式事务处理经验的话,这个问题就可以理解为是送分题,说实话有实际分布式事务经验的朋友估计不到40%。
如果没有呢!这个没有,还要分两种:一种是真的没接触过,这部分应该占40%,另外一种是接触到了,但是自己并不知道,这部分人大概占20%。
很容易被认为不是分布式事务的:采用消息队列、消息表(临时表、中间表)、定时任务等实现的最终一致性,很多都是分布式事务的解决方案。
针对分布式事务,我也整理了相关面试题:
另外,我也自研了《追问试面试》系列。
加入知识星球,即可获取,目前知识星球是起步阶段,超级划算。