当前位置: 首页 > 科技观察

什么是分布式事务,解决方案是什么?

时间:2023-03-15 23:27:05 科技观察

什么是分布式事务?答:一个大的操作是由不同的小操作组成的。这些小操作分布在不同的服务器上。分布式事务需要确保这些小操作要么全部成功,要么全部失败。本质上,分布式事务是为了保证不同数据库的数据一致性。分布式事务的原因?1数据库分库分表当单个数据库表中的数据达到千万级时,就需要考虑分库分表,那么原来的一个数据库就会变成多个数据库。比如一个操作同时操作01库和02库,需要保证数据的一致性,那么就必须使用分布式事务。2SOA的应用所谓SOA就是对业务的服务。比如在电商平台下单,会调用库存服务扣除库存,使用订单服务更新订单数据。然后设计订单数据库和库存数据库。为了保证数据的一致性,需要分布式事务。总结:其实以上两种场景,归根结底是需要操作多个数据库,并保证数据的一致性,从而产生分布式事务。分布式事务解决方案1.两阶段提交(2PC)XA是Tuxedo提出的一种分布式事务协议。XA大致分为两部分:事务管理器和本地资源管理器。其中,本地资源管理器往往由数据库来实现。比如Oracle、Mysql等数据库都实现了XA接口,事务管理器作为全局调度器,负责本地各种资源的提交和回滚。XA实现分布式事务的原理如下:总结两阶段提交看似可以提供原子操作,但它有几个缺点:同步阻塞问题:在执行过程中,所有参与的节点都是事务阻塞。当参与者占用公共资源时,其他第三方节点访问公共资源时必须被阻止。单点故障:由于(事务管理器)协调器的重要性,一旦协调器发生故障。(本地资源管理器)参与者将永远阻塞。尤其是在第二阶段,如果协调器失效,所有参与者仍处于锁定事务资源的状态,无法继续完成事务操作。(如果协调者挂掉了,可以重新选举一个协调者,但是不能解决参与者因协调者宕机而阻塞的问题)数据不一致:在二阶段提交的第二阶段参与者发送commit请求,在发送commit请求的过程中出现本地网络异常或者协调者失败,会导致只有部分参与者收到commit请求。这些参与者收到提交请求后,将执行提交操作。但是其他没有收到提交请求的机器是不能执行事务提交的。从而导致整个分布式系统出现数据不一致的情况。第二阶段无法解决的问题:参与者发送commit消息后宕机,唯一收到这条消息的协调者也同时宕机。那么即使协调者通过选举协议产生了新的协调者,这个事务的状态也是不确定的,没有人知道这个事务是否已经提交。2、三阶段提交(3PC)3PC实际上是在2PC的基础上增加了CanCommit阶段,是2PC的变种,引入了超时机制。一旦事务参与者长时间没有收到Coordinator的Commit请求,就会自动进行本地提交,比较有效的解决了Coordinator的单点故障问题。但是,性能和数据一致性的问题并没有得到根本解决。3PC分为三个阶段:CanCommit、PreCommit、DoCommit。CanCommit阶段与2PC的准备阶段非常相似。协调者向参与者发送提交请求。如果参与者可以提交,则返回Yes响应,否则返回No响应。事务查询:协调者向参与者发送CanCommit请求。询问是否可以执行事务提交操作。然后开始等待参与者的响应Response反馈:参与者收到CanCommit请求后,一般情况下,如果参与者认为交易可以成功执行,就会返回Yes响应,进入就绪状态。否则,返回NoPreCommit阶段。协调者根据参与者的响应决定是否可以进行事务的PreCommit操作。根据响应,有两种可能:如果协调者得到所有参与者的Yes,那么交易的执行就会被执行。发送预提交请求:协调者向参与者发送PreCommit请求,进入Prepared阶段。事务预提交:参与者收到PreCommit请求后,将执行事务操作,并在事务日志中记录undo和redo信息。响应反馈:如果参与者成功执行交易操作,将返回ACK响应并开始等待最终命令。如果任何参与者向协调器发送No响应,或者等待超时,或者协调器没有收到参与者的响应,则事务被中断。发送中止请求:协调器向所有参与者发送中止请求。中断事务:参与者收到协调器的中止请求后(或超时后,尚未收到协调器的请求),中断事务。doCommit阶段,该阶段真正的事务提交,也可以分为以下两种情况:执行提交并发送提交请求:Coordinator收到参与者发送的ACK响应,则进入提交状态从预提交状态。并向所有参与者发送doCommit请求。事务提交:参与者收到doCommit请求后,进行正式的事务提交,事务提交完成后释放所有事务资源。响应反馈:事务提交后,向协调器发送ACK响应。完成交易:协调者收到所有参与者的ACK响应后,交易完成。中断事务如果协调器没有收到参与者发送的ACK响应(可能是接收方没有发送ACK响应,或者响应超时),那么就会执行中断事务。发送中断请求:协调器向所有参与者发送中止请求事务回滚:参与者收到中止请求后,使用阶段2记录的undo信息执行事务回滚操作,并释放所有业务资源。反馈结果:参与者完成事务回滚后,向协调者发送ACK消息。中断事务:协调器收到参与者反馈的ACK报文后,执行事务的中断。原理图如下:总结与2PC相比,3PC对协调者和参与者都设置了超时时间,而2PC只有协调者有超时机制。本次优化解决了参与者长时间无法与协调节点通信时无法释放资源的问题,因为参与者本身有超时机制,超时后会自动执行本地commit释放资源。而且这种机制也减少了整个交易的阻塞时间和范围。但是数据一致性的问题仍然没有解决,即参与者收到PreCommit请求并等待最终指令后,如果此时协调者无法与参与者正常通信,参与者将继续提交事务,导致数据不一致。3.补偿交易(TCC)TCC(Try-Confirm-Cancel)也叫补偿交易。其实和2PC、3PC一样,只是分布式事务的一种实现。分为三个操作:Try阶段:主要是对业务系统进行检测和资源预留。确认阶段:确认业务操作的执行。取消阶段:取消业务操作的执行。TCC事务的处理流程与2PC两阶段提交类似,但2PC通常是在DB层面,而TCC本质上是应用层面的2PC,需要通过业务逻辑来实现。它的优点是允许应用程序自己定义数据库操作的粒度,减少锁冲突和提交吞吐量。但是对应用程序的侵入性很强,业务逻辑的每个分支都需要实现try、confirm、cancel这三个操作。TCC的示意图如下:4.消息事务+最终一致性所谓消息事务就是基于消息中间件的两阶段提交,本质上是中间件的一种特殊用途。它将本地事务和发送消息放在一个分布式事务中,保证要么本地操作成功,外发消息成功,要么都失败。开源的RocketMQ支持此功能。具体原理如下:步骤如下:服务A向消息中间件发送准备消息。消息中间件保存准备好的消息并返回成功。服务A执行本地事务。服务A向消息中间件发送提交消息,服务B收到消息后执行本地事务。基于消息中间件的两阶段提交常用于高并发场景。一个分布式事务拆分为一个消息事务(服务A的本地操作+消息)+服务B的本地操作,其中服务B的操作由消息Driver决定,只要消息事务成功,那么服务A必须成功,消息必须发送出去。这时候服务B会收到消息进行本地操作。如果本地操作失败,则重新提交消息,直到服务B成功。这样就变相的实现了A和B之间的分布式事务。以上步骤可能存在异常,我们现在分析一下:如果第1步出错:整个事务失败,服务A的本地操作不会执行。步骤2错误:整个事务失败,服务A的本地操作不会执行。第三步错误:需要回滚预备消息。服务A实现了一个消息中间件回调接口。消息中间件会不断执行回调接口,检查服务A的事务执行是否成功,如果失败则回滚准备消息。第4步报错:此时服务A本地事务成功,但消息中间件不需要回滚。实际上,消息中间件可以通过回调接口检查服务A是否执行成功。此时服务不需要发送提交消息,消息中间件可以自行提交消息完成整个消息事务。