分布式事务原理
什么是分布式事务
分布式对应的是单体架构,互联网早起单体架构是非常流行的,好像是一个家族企业,大家在一个家里劳作,单体架构如下图:
但是随着业务的复杂度提高,大家族人手不够,此时不得不招人,这样逐渐演变出了分布式服务,互相协作,每个服务负责不同的业务,架构如下图:
因此需要服务与服务之间的远程协作才能完成事务,这种分布式系统环境下由不同的服务之间通过网络远程协作完成事务称之为分布式事务,例如用户注册送积分事务、创建订单减库存事务,银行转账事务等都是分布式事务。
典型的场景就是微服务架构 微服务之间通过远程调用完成事务操作。比如:订单微服务和库存微服务,下单的同时订单微服务请求库存微服务减库存。简言之:跨JVM进程产生分布式事务。
什么是CAP原则
CAP原则又叫CAP定理,同时又被称作布鲁尔定理(Brewer's theorem),指的是在一个分布式系统中,不可能同时满足以下三点。
1、一致性(Consistency)
指强一致性,在写操作完成后开始的任何读操作都必须返回该值,或者后续写操作的结果。
也就是说,在一致性系统中,一旦客户端将值写入任何一台服务器并获得响应,那么之后client从其他任何服务器读取的都是刚写入的数据一致性保证了不管向哪台服务器写入数据,其他的服务器能实时同步数据
2、可用性(Availability)
可用性(高可用)是指:每次向未崩溃的节点发送请求,总能保证收到响应数据(允许不是最新数据)。
3、分区容忍性(Partition tolerance)
分布式系统在遇到任何网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务,也就是说,服务器A和B发送给对方的任何消息都是可以放弃的,也就是说A和B可能因为各种意外情况,导致无法成功进行同步,分布式系统要能容忍这种情况。除非整个网络环境都发生了故障。
4、为什么只能在A和C之间做出取舍?
分布式系统中,必须满足 CAP 中的 P,此时只能在 C/A 之间作出取舍。
如果选择了CA,舍弃了P,说白了就是一个单体架构。
一致性有几种分类
CAP理论告诉我们只能在C、A之间选择,在分布式事务的最终解决方案中一般选择牺牲一致性来获取可用性和分区容错性。
这里的 “牺牲一致性” 并不是完全放弃数据的一致性,而是放弃强一致性而换取弱一致性。
一致性可以分为以下三种:
- 强一致性
- 弱一致性
- 最终一致性
强一致性
系统中的某个数据被成功更新后,后续任何对该数据的读取操作都将得到更新后的值。
也称为:原子一致性(Atomic Consistency)、线性一致性(Linearizable Consistency)
简言之,在任意时刻,所有节点中的数据是一样的。例如,对于关系型数据库,要求更新过的数据能被后续的访问都能看到,这是强一致性。
总结:
- 一个集群需要对外部提供强一致性,所以只要集群内部某一台服务器的数据发生了改变,那么就需要等待集群内其他服务器的数据同步完成后,才能正常的对外提供服务。
- 保证了强一致性,务必会损耗可用性。
弱一致性
系统中的某个数据被更新后,后续对该数据的读取操作可能得到更新后的值,也可能是更改前的值。
但即使过了不一致时间窗口这段时间后,后续对该数据的读取也不一定是最新值。
所以说,可以理解为数据更新后,如果能容忍后续的访问只能访问到部分或者全部访问不到,则是弱一致性。
例如12306买火车票,虽然最后看到还剩下几张余票,但是只要选择购买就会提示没票了,这就是弱一致性。
最终一致性
是弱一致性的特殊形式,存储系统保证在没有新的更新的条件下,最终所有的访问都是最后更新的值。
不保证在任意时刻任意节点上的同一份数据都是相同的,但是随着时间的迁移,不同节点上的同一份数据总是在向趋同的方向变化。
简单说,就是在一段时间后,节点间的数据会最终达到一致状态。
弱一致性即使过了不一致时间窗口,后续的读取也不一定能保证一致,而最终一致过了不一致窗口后,后续的读取一定一致。
什么是Base理论
BASE理论是对CAP中的一致性和可用性进行一个权衡的结果,理论的核心思想就是:我们无法做到强一致,但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性。
BA(Basic Available)基本可用
整个系统在某些不可抗力的情况下,仍然能够保证“可用性”,即一定时间内仍然能够返回一个明确的结果。这里是属于基本可用。
基本可用和高可用的区别:
- “一定时间”可以适当延长 当举行大促(比如秒杀)时,响应时间可以适当延长。
- 给部分用户返回一个降级页面 给部分用户直接返回一个降级页面,从而缓解服务器压力。但要注意,返回降级页面仍然是返回明确结果。
S(Soft State)柔性状态
称为柔性状态,是指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统不同节点的数据副本之间进行数据同步的过程存在延时。
E(Eventual Consisstency)最终一致性
同一数据的不同副本的状态,可以不需要实时一致,但一定要保证经过一定时间后仍然是一致的。
分布式事务有哪几种解决方案
在分布式架构下,每个节点只知晓自己操作的失败或者成功,无法得知其他节点的状态。当一个事务跨多个节点时,为了保持事务的原子性与一致性,而引入一个协调者来统一掌控所有参与者的操作结果,并指示它们是否要把操作结果进行真正的提交或者回滚(rollback)。
2阶段提交(2PC)
二阶段提交协议(Two-phase Commit,即 2PC)是常用的分布式事务解决方案,即将事务的提交过程分为两个阶段来进行处理。
两个阶段分别为:
- 准备阶段
- 提交阶段
参与的角色:
- 事务协调者(事务管理器):事务的发起者
- 事务参与者(资源管理器):事务的执行者
准备阶段(投票阶段)
这是两阶段的第一段,这一阶段只是准备阶段,由事务的协调者发起询问参与者是否可以提交事务,但是这一阶段并未提交事务,流程图如下图:
- 协调者向所有参与者发送事务内容,询问是否可以提交事务,并等待答复
- 各参与者执行事务操作,将 undo 和 redo 信息记入事务日志中(但不提交事务)
- 如参与者执行成功,给协调者反馈同意,否则反馈中止
提交阶段
这一段阶段属于2PC的第二阶段(提交 执行阶段),协调者发起正式提交事务的请求,当所有参与者都回复同意时,则意味着完成事务,流程图如下:
- 协调者节点向所有参与者节点发出正式提交(
commit
)的请求。 - 参与者节点正式完成操作,并释放在整个事务期间内占用的资源。
- 参与者节点向协调者节点发送ack完成消息。
- 协调者节点收到所有参与者节点反馈的ack完成消息后,完成事务。
但是如果任意一个参与者节点在第一阶段返回的消息为终止,或者协调者节点在第一阶段的询问超时之前无法获取所有参与者节点的响应消息时,那么这个事务将会被回滚,回滚的流程图如下:
- 协调者节点向所有参与者节点发出回滚操作(
rollback
)的请求。 - 参与者节点利用阶段1写入的undo信息执行回滚,并释放在整个事务期间内占用的资源。
- 参与者节点向协调者节点发送ack回滚完成消息。
- 协调者节点受到所有参与者节点反馈的ack回滚完成消息后,取消事务。
不管最后结果如何,第二阶段都会结束当前事务。
二阶段提交的事务正常提交的完整流程如下图:
二阶段提交事务回滚的完整流程如下图:
举个百米赛跑的例子来具体描述下2PC的流程:学校运动会,有三个同学,分别是A,B,C,2PC流程如下:
裁判:A同学准备好了吗?准备进入第一赛道....
裁判:B同学准备好了吗?准备进入第一赛道....
裁判:C同学准备好了吗?准备进入第一赛道....
如果有任意一个同学没准备好,则裁判下达回滚指令
如果裁判收到了所有同学的OK回复,则再次下令跑......
裁判:1,2,3 跑............
A同学冲刺到终点,汇报给裁判
B,C同学冲刺失败,汇报给裁判
2PC的的优缺点
1、优点
尽量保证了数据的强一致,适合对数据强一致要求很高的关键领域。(其实也不能100%保证强一致)
2、缺点
二阶段提交看起来确实能够提供原子性的操作,但是不幸的是,二阶段提交还是有几个缺点的:
- 性能问题:执行过程中,所有参与节点都是事务阻塞型的。当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。
- 可靠性问题:参与者发生故障。协调者需要给每个参与者额外指定超时机制,超时后整个事务失败。协调者发生故障。参与者会一直阻塞下去。需要额外的备机进行容错。
- 数据一致性问题:二阶段无法解决的问题:协调者在发出
commit
消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了。那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交。 - 实现复杂:牺牲了可用性,对性能影响较大,不适合高并发高性能场景。
3阶段提交(3PC)
三阶段提交协议,是二阶段提交协议的改进版本,三阶段提交有两个改动点。
- 在协调者和参与者中都引入超时机制
- 在第一阶段和第二阶段中插入一个准备阶段。保证了在最后提交阶段之前各参与节点的状态是一致的。
也就是说,除了引入超时机制之外,3PC把2PC的准备阶段再次一分为二,这样三阶段提交就有CanCommit
、PreCommit
、DoCommit
三个阶段。处理流程如下:
CanCommit阶段
3PC的CanCommit
阶段其实和2PC的准备阶段很像。协调者向参与者发送commit
请求,参与者如果可以提交就返回Yes响应,否则返回No响应。