分布式事务的具体实现:两阶段提交(2PC)
🍔前言
”分布式事务“顾名思义,指的是涉及到多个分布式系统或者多个数据库的事务操作。在分布式系统中,如果一个事务涉及到多个独立的组件或者服务,每个组件或服务可能位于不同的物理节点上,那么这个事务就被称为分布式事务。
在分布式系统中实现分布式事务是一个复杂的问题,因为涉及到多个独立的组件或者服务,可能存在网络延迟、通信故障、节点故障等因素。为了保证分布式事务的一致性和可靠性,需要使用合适的事务管理协议和机制,如两阶段提交(2PC)、三阶段提交(3PC)、基于消息的事务、分布式事务管理器等。这些方法都旨在确保在分布式环境中执行的事务要么全部提交,要么全部回滚,从而保证数据的一致性。🤗
而两阶段提交又是较为简单和常用的实现协议,本文主要也是讲述两阶段提交的
简单贴下各协议的定义:
(可以先只看两阶段提交,其他还不参与讨论)
**两阶段提交(Two-Phase Commit,2PC)**是一种用于分布式系统中实现分布式事务的协议。它分为两个阶段:
准备阶段:事务协调者询问所有参与者是否准备好提交或者回滚事务,并等待它们的响应。
提交阶段:如果所有参与者都准备好提交,事务协调者通知它们提交事务;如果有任何一个参与者未能准备好或者出现错误,事务协调者通知它们回滚事务。
三阶段提交(3PC):三阶段提交是对两阶段提交的改进,通过在第一阶段引入额外的准备阶段来解决某些情况下的阻塞问题。在三阶段提交中,除了准备和提交阶段外,还有一个称为“预提交”或“预准备”阶段,用于减少参与者在第二阶段的等待时间。
基于消息的事务:在分布式系统中,可以使用消息队列等消息传递机制来实现事务的一致性。在这种方法中,事务的各个参与者将事务信息发送到消息队列中,协调者会根据消息的发送情况来决定事务是否提交或者回滚。
两阶段提交的改进:针对两阶段提交的一些不足之处,还有一些改进的方法,如柔性事务(Flexible Transactions)、Paxos协议、Raft算法等。这些方法都是针对分布式系统中事务一致性的改进和优化。
分布式事务管理器:一些分布式数据库系统或者中间件提供了分布式事务管理器(如Java Transaction API,JTA),它们提供了高级的事务管理功能,帮助开发者在分布式环境中管理事务。
🍟两阶段提交协议的实现和作用
MySQL的两阶段提交(Two-Phase Commit,2PC)是一种用于确保分布式事务的一致性的协议。。MySQL的两阶段提交协议包括以下两个阶段:(请仔细阅读两个阶段的具体实现)
- 准备阶段(Prepare Phase):
- 在这个阶段,事务的协调者(通常是MySQL服务器)会向所有涉及的数据库或者资源管理器发送准备请求。
- 每个数据库或者资源管理器收到准备请求后,会执行相应的操作,并且记录准备状态(prepared)。如果准备成功,就向协调者发送准备就绪的信号。
- 协调者等待所有参与者都发送准备就绪的信号,如果有任何一个参与者未能准备就绪或者出现了错误,协调者将会发送回滚请求给所有参与者。
- 提交阶段(Commit Phase):
- 如果所有的参与者都准备就绪,协调者会向它们发送提交请求。
- 参与者接收到提交请求后,会正式提交事务,并且释放相关资源。
- 如果有任何一个参与者未能接收到提交请求或者出现了错误,协调者将会发送回滚请求给所有参与者。
这些话说的有点笼统且并没有和具体数据库操作连接起来:更加详细的操作如下(👶也能看懂233):
第一阶段 - 准备阶段:
- 协调者发送准备请求: 协调者向所有参与者发送准备请求,询问它们是否可以执行事务操作,并等待它们的响应。
- 参与者准备就绪: 参与者在收到准备请求后,进行本地事务的准备工作,如锁定资源、写入日志等,并向协调者发送准备就绪的消息。
- 协调者等待响应: 协调者收到所有参与者的准备就绪消息后,等待一段时间以确保所有参与者都已准备就绪。
第二阶段 - 提交阶段:
- 协调者发送提交请求: 如果协调者收到了所有参与者的准备就绪消息,它会向所有参与者发送提交请求,要求它们提交事务。
- 参与者执行提交操作: 参与者在收到提交请求后,正式执行事务提交操作,并释放相关资源。如果提交成功,参与者会向协调者发送提交成功的消息;如果提交失败,参与者会向协调者发送提交失败的消息。
- 协调者等待结果: 协调者收到所有参与者的提交结果后,根据结果决定是否将事务标记为提交或者回滚。如果所有参与者都提交成功,协调者将向应用程序返回提交成功的消息;如果有任何一个参与者提交失败或者超时未响应,协调者将向应用程序返回提交失败的消息,并要求所有参与者回滚事务。
通过这两个阶段,MySQL的两阶段提交协议可以确保要么所有的数据库都成功提交事务,要么所有的数据库都回滚事务,从而保证了分布式系统中的数据一致性。
就像是军训一样,准备阶段:教官让所有同学都立正站好,所有同学都得对齐站好,谁没有站好,全部同学都得重新立正,直到所有同学都准备好,然后,训练阶段:同学们都站一排齐步走,只要有一个没走齐的就重新开始;(👴已经尽力去解释了,我相信即使没有学过计算机的应该也知道这玩意是什么了,嘿嘿);看着是不是毫无压力,
🌭两阶段提交的必要性
我们都知道了两阶段协议其实就是事务在分布式的具体实现;所以其也拥有了事务的特征:核心目的是确保分布式事务的原子性和一致性,即要么所有数据库都成功提交事务,要么都回滚事务,从而保证了数据的一致性。要是总结的话,两阶段提交协议的必要性包括以下几个方面:
- 数据一致性:在分布式系统中,由于涉及到多个独立的数据库或者资源管理器,可能出现某些数据库提交成功而其他数据库提交失败的情况,导致数据不一致。两阶段提交协议通过协调者的调度和协调,确保了要么所有数据库都成功提交事务,要么都回滚事务,从而保证了数据的一致性。
- 事务的原子性:原子性是事务的基本属性,表示事务要么全部提交成功,要么全部回滚失败。在分布式系统中,要保证所有参与者都能够按照一致的方式提交或者回滚事务,这就需要引入协调者来统一管理事务的提交和回滚过程,而两阶段提交协议提供了这样的机制。
- 避免数据丢失:两阶段提交协议确保了在所有数据库都准备就绪后才进行提交操作,避免了数据丢失或不完整的情况发生。即使在网络分区或者节点故障等异常情况下,协调者也能够根据参与者的响应情况来决定是否提交或者回滚事务,从而保证了数据的完整性和可靠性。
🍿实战案例
下边会以银行转账的项目案例来进一步说明其必要性(分布式多数据库系统)
假设有一个在线银行系统,允许用户进行转账操作。在这个系统中,每当用户发起一笔转账请求时,需要在转出账户和转入账户对应的数据库中进行更新操作。下面是针对这个场景的两阶段提交的必要性分析:
第一阶段 - 准备阶段:
- 用户A向用户B转账100元。系统需要在用户A的账户数据库和用户B的账户数据库中分别执行相应的更新操作。
- 在准备阶段,系统向用户A的账户数据库发送准备请求,要求进行扣款操作,并等待其响应。
- 收到准备请求: 转出账户数据库收到系统的准备请求后,首先检查账户余额是否足够扣款,并锁定转出账户以防止并发操作。
- 准备就绪响应: 如果账户余额足够扣款,并且成功锁定转出账户,转出账户数据库向系统发送准备就绪的响应,表示可以执行扣款操作。
3.同时,系统向用户B的账户数据库发送准备请求,要求进行存款操作,并等待其响应。
- 收到准备请求: 转入账户数据库收到系统的准备请求后,会锁定转入账户以防止并发操作,并准备执行存款操作。
- 准备就绪响应: 转入账户数据库向系统发送准备就绪的响应,表示可以执行存款操作。
第二阶段 - 提交阶段:
- 当所有数据库都准备就绪后,系统向所有数据库发送提交请求。
- 用户A的账户数据库接收到提交请求后,正式执行扣款操作,并将结果持久化到数据库中。
- 收到提交请求: 如果在准备阶段收到了系统的提交请求,转出账户数据库会执行实际的扣款操作,并将转出账户的余额更新到数据库中。
- 提交成功响应: 扣款操作成功完成后,转出账户数据库向系统发送提交成功的响应,表示转出账户的扣款操作已经完成并成功提交。
- 回滚操作: 如果在准备阶段或提交阶段出现任何错误或失败情况,转出账户数据库会执行回滚操作,取消已经扣款的操作,并释放转出账户的锁定状态。
3.用户B的账户数据库接收到提交请求后,正式执行存款操作,并将结果持久化到数据库中。
- 收到提交请求: 在收到系统的提交请求后,转入账户数据库会执行实际的存款操作,并将转入账户的余额更新到数据库中。
- 提交成功响应: 存款操作成功完成后,转入账户数据库向系统发送提交成功的响应,表示转入账户的存款操作已经完成并成功提交。
- 回滚操作: 如果在准备阶段或提交阶段出现任何错误或失败情况,转入账户数据库会执行回滚操作,取消已经执行的存款操作,并释放转入账户的锁定状态。
必要性分析:
- 数据一致性:如果不使用两阶段提交,可能会出现一种情况,即用户A的账户数据库已经扣款成功,但是用户B的账户数据库却未能成功存款。这样会导致转账操作的数据不一致,用户的资金可能会出现异常。
- 保证事务的完整性:使用两阶段提交可以确保要么转账操作的所有数据库都成功提交,要么都回滚,从而保证了整个事务的完整性。
- 避免数据丢失:两阶段提交可以确保在所有数据库都准备就绪后才进行提交操作,避免了数据丢失或不完整的情况发生,提高了系统的稳定性和可靠性。
🧇总结
通过以上的分析,我总结出来一句话==“两阶段提交”这个新名词落实到具体作用上其实就是分布式事务的一种具体实现方法,他是定义的一种新协议,用于在分布式数据库中实现类似于事务的作用,以保证数据的一致性。==
虽然这篇博客有点点长或者说基础~~(有点冗长)~~🤐,甚至总结起来只有最后的这一句话,但是通篇看下来有助于复习事务的相关知识点,也可以对分布式事务有个大致的了解,对于之后的学习还是很有帮助的;🤤
通过这些概念的学习,在之后的go语言开发中我们会用到go-zero框架,他是基于分布式理念的微服务框架,到那时会我们对分布式事务的实现有一个更深层次的理解和应用;🥰