分布式事务
- 数据库事务
-
原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。原子性是一种业务述求,就是可能很多时候,很多业务是独立的,但是多个事情不可分割,要么都发生,要么不发生,也是常有的 -
一致性(Consistency)
事务前后数据的完整性必须保持一致。在原子性的述求下,保证数据一致性【对外的正确性】是最基本要求,既然有关联,就得有解决方案,方案就是想法子让一致 -
隔离性(Isolation)
事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。只要是多个事情就有中间状态,所谓强一致性就是,尽管我有中间状态,用redo,undo日志,事务开启,提交等,进行隔离,保证强一致性(其实所谓的最终一致性,就是没有隔离,看见了中间状态,包括一部分提交,一部分还没提交,也包括一部分提交,一部分失败了) -
持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。持久性是数据库的最基本功能,都不能保证持久化,还要数据干嘛
- 分布式事务
2.1场景包括
- 夸库
- 分库分表
- 夸应用
2.2 CAP理论
当单体应用或者数据库扛不住业务,分布式成为必然(或者说为了满足更大体量的业务要求,我们不得不分布式),显然单机ACID还是我们必须的,但是分布式又带来新的挑战可用性和分区容错性,这里为什么不变讨论AID呢原子性是一个业务述求,不要过多强调,如果没有原子性的业务述求,就不存在后续种种,隔离性其实和强一致性和若一致性性,包含在一致性里面了,BASE理论会提到,持久性数据库可以保证的,不会收到分布式的影响。简单讲:1. 原子性是一个基本业务述求,不会因为你分布式,业务述求就消失,2.持久性分布式后,数据库也能保证; 3. 一致性(包括隔离性)我们在分布式系统如何解决呢???
- Consistency(一致性)本系统的客户端的一种承诺:要么我给您返回一个错误,要么我给你返回绝对一致的最新数据,不难看出,其强调的是数据正确。其实这个和数据库的一致性同理
- Availability(可用性)任何客户端的请求都能得到响应数据,不会出现响应错误。换句话说,可用性是站在分布式系统的角度,对访问本系统的客户的另一种承诺:我一定会给您返回数据,不会给你返回错误,但不保证数据最新,强调的是不出错
- Partition tolerance(分区容忍性)由于分布式系统通过网络进行通信,网络是不可靠的。当任意数量的消息丢失或延迟到达时,系统仍会继续提供服务,不会挂掉。换句话说,分区容忍性是站在分布式系统的角度,对访问本系统的客户端的再一种承诺:我会一直运行,不管我的内部出现何种数据同步问题,强调的是不挂掉。
CAP只能3选2,网上都说P必选,其实是一种误导。首先客户最基本述求是原子性(持久性是一个前提,磁盘硬件解决的,其实事务都是在持久性的前提下,围绕原子性的需求来讨论的,原子性的述求带来了一致性和隔离性的问题要解决),分布式以后,业务多出来一个述求可用性,应用多了,本来业务体量大了后就扛不住,分布式通信开销也成为了瓶颈。我理解分区容错性业务感知是不明显,因为99%的情况,系统通信都没啥问题,我们努力去解决AC问题就行特别注意,不是说放弃P,AC就自然满足了,我们也是需要去解决的,选了AC,无论如何也解决不了P的问题,如何解决呢,性能优化,没事就开启长事务,搞不好就超时了,数据库一致性还是要继续用起来的。1%的情况,系统通信故障(包括业务接口报错,或者不能扣钱等)我们可以放弃吗?显然在不行,在这个P的前提下,我们只能选择AP和CP,选择CP最简单,直接放弃了可用性,客户哪里能忍,一般我们选择AP但是C也不能彻底放弃,当P出现时候我们选择AP,暂时放弃C,但P很快会消失,消失后C难道也不管吗?显然不行
CP系统代表:zookeeper(leader宕机后,选举阶段,系统不可用)
AP系统代表:Eureka
我理解的XA(两阶段或三阶段提交),更偏向CP一些,基本还是靠长事务来解决的,只是做了些优化,最终也不能保证CP,局部选择了AP
2.3 BASE理论
AP虽然比CP复杂,但是用户体验更好,但是C对系统数据很重要,绝不可放弃,因此诞生了AP解决方案的BASE理论,BASE是CP(强一致性)和AP(强可用性)权衡的结果
- Basically Available(基本可用)
响应时间上的损失:正常情况下,处理用户请求需要0.5s返回结果,但是由于系统出现故障,处理用户请求的时间变成3s。并不是无脑处理,还是给C最终一致性,做些基础准备,尽量保证A,但是也做一些牺牲
系统功能上的损失:正常情况下,用户可以使用系统的全部功能,但是由于系统访问量突然剧增,系统的非核心功能无法使用。优先保证可用,极限情况选择CP,因为无脑AP可能脏数据不是系统能吃得消的 - Soft state(软状态)
数据同步允许一定的延迟。放弃了强一致性 - Eventually consistent(最终一致性)
系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态,不要求实时。但是要求最终能一致
2.4 分布式事务解决方案
- 基础理论Paxos算法,RATF算法
- 2PC (全局锁,悲观锁,一把大锁全锁住)
- 3PC(XA)(全局锁,悲观锁,一把大锁全锁住)
- TCC (分段锁,悲观锁,各自锁住,然后各自内部保证)
- SAGA (乐观锁,先按照能成功处理,成功不了再想办法兜底)
- TA(可以简单理解阿里实现的应用层的XA)
2.4.1 Paxos算法
假设:消息通信,消息不可靠,应用也不可靠
Paxos算法运行在允许宕机故障的异步系统中,不要求可靠的消息传递,可容忍消息丢失、延迟、乱序以及重复。它利用大多数 (Majority) 机制保证了2F+1的容错能力,即2F+1个节点的系统最多允许F个节点同时出现故障
https://zhuanlan.zhihu.com/p/31780743
- 大家没聚在一起,只能通过消息通信(其实就是分布式),不会故意下达
- 消息谁能保证及时送达(网络不能保证,送信的可能死掉了),但是可能重发,足够长时间一定送达
- 正常情况大家不会拒绝(不会故意下达错误的指令,就是明明自己提交了,还说发没提交的信息),但是由于死掉了,或者暂时处理不了,或者条件不允许可能会拒绝
1、选择一个节点成为leader/proposer,必须有个leader(其实是Multi-Paxos),leader如何产生呢,可以用Basic-Paxos算法,就是分布式广播选举,比如大家先通信一波,确认各自的序号,然后大家都选最大的,然后大家都同意,结束,但是,网络故障,可能出现分区,A以为最大是3,B以为最大是5,
2、leader选择一个值,发送到所有的节点(Paxos中称之为acceptor),这个消息被称为“接受请求”消息。acceptor可以回应接受或拒绝。一次决议只解决一个问题
3、一旦节点中的大多数回应接受,共识就能达成,协调者将“提交”消息发送到所有节点,leader来统筹达成共识的问题,一旦达成共识,就群发,所有人都会尽力去做
- 获取一个Proposal ID n,为了保证Proposal ID唯一,可采用时间戳+Server ID生成;
- Proposer向所有Acceptors广播Prepare(n)请求;
- Acceptor比较n和minProposal,如果n>minProposal,minProposal=n,并且将 acceptedProposal 和 acceptedValue 返回;
- Proposer接收到过半数回复后,如果发现有acceptedValue返回,将所有回复中acceptedProposal最大的acceptedValue作为本次提案的value,否则可以任意决定本次提案的value;
- 到这里可以进入第二阶段,广播Accept (n,value) 到所有节点;
- Acceptor比较n和minProposal,如果n>=minProposal,则acceptedProposal=minProposal=n,acceptedValue=value,本地持久化后,返回;否则,返回minProposal。
- 提议者接收到过半数请求后,如果发现有返回值result >n,表示有更新的提议,跳转到1;否则value达成一致。
2.4.1 2PC(全局锁)
拆分了数据库事务的执行和提交(也可能是回滚)动作
两阶段提交:事务参与者,第一阶段只执行事务,但是不提交,执行完成告知事务协调者TC,TC收到所有事务参与者的准备完成后,给所有参与者发送提交commit指令,然后都开始提交。问题:阻塞、单点、以及第二阶段协调者挂了,数据不一致
![请添加图片描述](https://img-blog.csdnimg.cn/2beacc96d5934b99aa4f1a914e501038.jpeg
2.4.2 3PC(全局锁)
1. 校验要前置而不是一味兜底、2. 阻塞要搭配超时使用,当然超时也会引发新的问题,3PC并没有解决这些问题
三阶段提交是2PC的优化,前置检查一般就是检查资源是否具备,所是否能获取等等,而不是上来大家都直接执行。2PC比3PC简单,如果执行都没问题,那么第3阶段就是提交动作,没啥问题,如果是回滚动作,前面大叫都累死,结果要回滚,加入前置校验,可以很大程度避免第三阶段回滚,就是做一步前置检查,1是避免不必要的执行动作,2是校验后各执行者事务也会快(比如多半锁就可以立即获得),减轻了阻塞。因为终究还是阻塞的形式,超时机制不可少,避免一直卡死,但是也带来了数据不一致的风险
2.4.2 TCC (悲观锁)
2PC和3PC都是拆分了数据库的事务,也就是数据库使用长事务。TCC没有拆分数据库的事务执行和提交,是业务层面的拆分。1.资源预留与冻结,需要改造业务以及表结构;如果预留成功,就各自执行提交(就需要各自系统保证能处理完成了),否则就取消预留,解除冻结,(同样需要各自系统保证能取消掉)
好处:各系统的事务彻底隔离开了
缺点:1.改造成本大, 2. 各系统内部不管是执行提交,还是取消预留都要各自保证,3. 也是最终一致性
2.4.2 SAGA (乐观锁)
TCC是直接改造原有逻辑,而SAGA是原有逻辑不变,作补偿
阶段一:当没有分布式问题(就是一般不会出问题,大胆点),各自分头执行
阶段二:有两条路子,路子1.依次回滚(回滚链路需要编排)路子2.往前恢复,直到都成功(一般有重试,或者换条路子重试)
重试就需要幂等,有些没办法直接重试,或者下游系统不然重试,或者由于前期的乐观数据已经有所变化,此时可能需要先查一下其他系统或者自己系统数据的状态,然后再决定如何重试,也是需要编排的
好处:1. 各系统的事务彻底隔离开了; 2. 现有的业务逻辑不变,专门针对出问题找办法解决
缺点:1. 需要编排,排查定位问题复杂; 2. 问题链路处理很复杂,有时候有系统不能回退(比如火箭已经发射,比如开发还没支持),有时其他系统不能重试,3. 只能保证最终一致性
那么我们可以让其他系统都支持回退或者重试吗,可以是可以,但是这个SAGA的初衷有些相互违背,因为TCC就是为了解决1%的问题,对99%的没有问题的情形改造,SAGA就是希望,各自99%,希望达到99.99999%的系统,自己来想办法保证