分布式事务解决方案
- 2pc 两段提交协议
- 3pc三段提交协议
- Tcc (两段提交)
- Mq 补偿与重试机制
- 其他补偿方式(回调)
- rocketmq事务消息
- LCN
- 分布式一致性算法——Paxos
本章学习点
- 全局事务
- 本地事务XA接口
- cpa\base理论
- 柔性事务与刚性
分布式事务产生原因
- 事务
acid(原子、持久、一致、隔离)
隔离级别: 脏读、更新丢失、可重复读、读取已经提交
- 分布式事务
产生原因:
每个服务有独立数据源
服务调用异常rpc接口服务不能回滚
分布式事务理论
- CPA理论
数据一致性
服务可用性(响应,不能一直等待)
分区容错(某个节点发生故障也能满足一致性问题)
- Base理论(柔性事务)
1、基本可用(服务降级,返回错误吗)
2、软状态(系统中间状态,不能响应整体可用性)
3、最终一致性 (数据最终一致性)
- 柔性与刚性事务
刚性事务:
满足acid.
柔性事务:
两段提交、补偿
异步通知
base理论
分布式事务解决方案
1、两段提交协议2pc
1、协调者给每个参与者发送通知,并回复协调者
通知作用:开启事务、确认业务逻辑执行没有任何异常
.
存在问题:第一次提交时,存在参与者一直不能回复,
协调者 一直等待回复,必须采用超时机制回滚
2、向每个数据源发送通知结果,进行提交commit
第一阶段失败,第二阶段直接发送回滚通知
- 三段提交协议3pc
- 全局事务
- 本地事务
- XA接口
- Jta
2、MQ解决分布式事物
- 重试(存在延时占资源)与补偿机制
- 幂等防止重复消费
- 定时job进行补偿保证最终一致性
- 消费者程序bug,不能进行重试,必须做日志记录 + 定时job处理
2PC
在分布式系统中,每个节点虽然可以知晓自己的操作时成功或者失败,却无法知道其他节点的操作的成功或失败(只知道自己有时间可以玩王者荣耀,不知道其他人有没有)。
.
一个事务跨越多个节点时,为了保持事务的ACID特性,需要引入一个作为协调者的组件来统一掌控所有参与者的操作结果并最终指示这些节点是否要把操作结果进行真正的提交(组织者通知各位参与者一起进入游戏房间)。
.
因此,二阶段提交的算法思路可以概括为:参与者将操作成败通知协调者,再由协调者根据所有参与者的反馈情报决定各参与者是否要提交操作还是中止操作。
- 第一阶段:准备阶段(投票阶段)
事务协调者给每个参与者发送Prepare消息,每个参与者要么直接返回失败(告知组织者自己没时间,不能一起玩游戏),要么在本地执行事务(登录王者荣耀),但不提交(先不开始游戏)。
可以进一步将准备阶段分为以下三个步骤:
1)协调者节点向所有参与者节点询问是否可以执行提交操作,并开始等待各参与者节点的响应。(询问是否可以一起玩游戏)
2)参与者节点执行询问发起为止的所有事务操作,并将Undo信息和Redo信息写入日志。(登录王者荣耀游戏)
3)各参与者节点响应协调者节点发起的询问。如果参与者节点的事务操作实际执行成功,则它返回一个”同意”消息;(告知组织者自己已经登录成功)如果参与者节点的事务操作实际执行失败,则它返回一个”中止”消息。(告知组织者自己暂时无法一起玩游戏,如自己的账号被限制无法打排位)
- 第二阶段:提交阶段(执行阶段)
如果协调者收到了参与者的失败消息或者超时(有人不能一起玩游戏,或者一直没有回复),直接给每个参与者发送回滚消息(告知其他人,暂时取消游戏);否则,发送提交消息(邀请大家进入游戏房间);参与者根据协调者的指令执行提交或者回滚操作(进入房间一起玩游戏或者退出游戏去做别的事情)。
当协调者节点从所有参与者节点获得的相应消息都为”同意”时:
1)协调者节点向所有参与者节点发出”正式提交”的请求(要求所有已登录的朋友加入游戏房间)。
2)参与者节点正式完成操作,并释放在整个事务期间内占用的资源(接受邀请,进入房间)。
3)参与者节点向协调者节点发送”完成”消息(点击"准备",进入准备状态)。
4)协调者节点受到所有参与者节点反馈的”完成”消息后,完成事务(进入王者峡谷)。
如果任一参
与者节点在第一阶段返回的响应消息为”中止”,或者 协调者节点在第一阶段的询问超时之前无法获取所有参与者节点的响应消息时:
1)协调者节点向所有参与者节点发出”回滚操作”的请求(告知所有人取消游戏)。
2)参与者节点利用之前写入的Undo信息执行回滚,并释放在整个事务期间内占用的资源(退出游戏,去做自己的事情)。
3)参与者节点向协调者节点发送”回滚完成”消息(告诉组织者自己知道了,后面有机会再玩)。
4)协调者节点受到所有参与者节点反馈的”回滚完成”消息后,取消事务(取消本次游戏活动)。
分布式系统的2PC阶段一样存在,分别对应以下问题
1、同步阻塞问题。执行过程中,所有参与节点都是事务阻塞型的。当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。
2、单点故障。由于协调者的重要性,一旦协调者发生故障。参与者会一直阻塞下去。尤其在第二阶段,协调者发生故障,那么所有的参与者还都处于锁定事务资源的状态中,而无法继续完成事务操作。(如果是协调者挂掉,可以重新选举一个协调者,但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问题)
3、数据不一致。在二阶段提交的阶段二中,当协调者向参与者发送commit请求之后,发生了局部网络异常或者在发送commit请求过程中协调者发生了故障,这回导致只有一部分参与者接受到了commit请求。而在这部分参与者接到commit请求之后就会执行commit操作。但是其他部分未接到commit请求的机器则无法执行事务提交。于是整个分布式系统便出现了数据部一致性的现象。
4、二阶段无法解决的问题:协调者再发出commit消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了。那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交。
3PC
3PC,就是把2PC的准备阶段再次一分为二,组成了三阶段。
在第一阶段,只是询问所有参与者是否可以执行事务操作,并不在本阶段执行事务操作。当协调者收到所有的参与者都返回YES时,在第二阶段才执行事务操作,然后在第三阶段在执行commit或者rollback。
这样三阶段提交就有CanCommit(事务询问)、PreCommit(事务执行)、DoCommit(事务提交)三个阶段。
- CanCommit
3PC的CanCommit阶段其实和2PC的准备阶段很像。协调者向参与者发送commit请求,参与者如果可以提交就返回Yes响应,否则返回No响应。
1、事务询问:协调者向参与者发送CanCommit请求。询问是否可以执行事务提交操作。然后开始等待参与者的响应。
2、响应反馈:参与者接到CanCommit请求之后,正常情况下,如果其自身认为可以顺利执行事务,则返回YES响应,并进入预备状态。否则反馈NO
- PreCommit阶段
协调者根据CanCommit阶段参与者的反应情况来决定是否可以进行事务的PreCommit操作。
- 假如协调者从所有的参与者获得的反馈都是YES响应,那么就会执行事务的预执行:
- 假如有任何一个参与者向协调者发送了NO响应,或者等待超时之后,协调者都没有接到参与者的响应,那么就执行事务的中断。
1、发送中断请求:协调者向所有参与者发送abort请求。
2、中断事务:参与者收到来自协调者的abort请求之后(或超时之后,仍未收到协调者的请求),执行事务的中断。
- doCommit阶段
该阶段进行真正的事务提交,也可以分为以下两种情况。
如果协调证收到所有参与者的事务执行后的ACK响应,则发生如下事情:
1、发送提交请求:协调接收到参与者发送的ACK响应,那么他将从预提交状态进入到提交状态。并向所有参与者发送doCommit请求。
2、事务提交:参与者接收到doCommit请求之后,执行正式的事务提交。并在完成事务提交之后释放所有事务资源。
3、响应反馈:事务提交完之后,向协调者发送Ack响应。
4、完成事务:协调者接收到所有参与者的ack响应之后,完成事务。
如果协调者没有接收到参与者发送的ACK响应(可能是接受者发送的不是ACK响应,也可能响应超时),那么就会执行中断事务。
1、发送中断请求:协调者向所有参与者发送abort请求
2、事务回滚:参与者接收到abort请求之后,利用其在阶段二记录的undo信息来执行事务的回滚操作,并在完成回滚之后释放所有的事务资源。
3、反馈结果:参与者完成事务回滚之后,向协调者发送ACK消息
4、中断事务:协调者接收到参与者反馈的ACK消息之后,执行事务的中断。
还有一种情况,如果参与者无法及时接收到来自协调者的doCommit或者abort请求时,会在等待超时之后,会继续进行事务的提交。
3PC无法解决的问题
在doCommit阶段,如果参与者无法及时接收到来自协调者的doCommit或者abort请求时,会在等待超时之后,会继续进行事务的提交。
所以,由于网络原因,协调者发送的abort响应没有及时被参与者接收到,那么参与者在等待超时之后执行了commit操作。这样就和其他接到abort命令并执行回滚的参与者之间存在数据不一致的情况。
3PC比2PC区别
1、降低同步阻塞。
在3PC中,第一阶段并没有让参与者直接执行事务,而是在第二阶段才会让参与者进行事务的执行。大大降低了阻塞的概率和时长。并且,在3PC中,如果参与者未收到协调者的消息,那么他会在等待一段时间后自动执行事务的commit,而不是一直阻塞。
2、提升了数据一致性
2PC中有一种情况会导致数据不一致,如在2PC的阶段二中,当协调者向参与者发送commit请求之后,发生了网络异常,只有一部分参与者接受到了commit请求。而在这部分参与者接到commit请求之后就会执行commit操作。但是其他部分未接到commit请求的机器则无法执行事务提交。于是整个分布式系统便出现了数据不一致性的现象。
这种情况在3PC的场景中得到了很好的解决,因为在3PC中,如果参与者没有收到协调者的消息时,他不会一直阻塞,过一段时间之后,他会自动执行事务。这就解决了那种协调者发出commit之后。
另外,2PC还有个问题无法解决。那就是协调者再发出commit消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了。那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交。
这种情况在3PC中是有办法解决的,因为在3PC中,选出新的协调者之后,他可以咨询所有参与者的状态,如果有某一个处于commit状态或者prepare-commit状态,那么他就可以通知所有参与者执行commit,否则就通知大家rollback。因为3PC的第三阶段一旦有机器执行了commit,那必然第一阶段大家都是同意commit的,所以可以放心执行commit。