1 事务
事务可以看做是一次大的活动,它由不同的小活动组成,这些活动要么全部成功,要么全部失败。
2 本地事务
在计算机系统中,更多的是通过关系型数据库来控制事务,这是利用数据库本身的事务特性来实现的,因此叫数据库事务,由于应用主要靠关系数据库来控制事务,而数据库通常和应用在同一个服务器,所以基于关系型数据库的事务又被称为本地事务。
数据库事务的四大特性:ACID
A(Atomic):原子性,构成事务的所有操作,要么都执行完成,要么全部不执行,不可能出现部分成功部分失败的情况。
C(Consistency):一致性,在事务执行前后,数据库的一致性约束没有被破坏。比如:张三向李四转 100 元,转账前和转账后的数据是正确状态这叫一致性,如果出现张三转出 100 元,李四账户没有增加 100 元这就出现了数 据错误,就没有达到一致性。
I(Isolation):隔离性,数据库中的事务一般都是并发的,隔离性是指并发的两个事务的执行互不干扰,一个事务不能看到其他事务的运行过程的中间状态。通过配置事务隔离级别可以比避免脏读、重复读问题。
D(Durability):持久性,事务完成之后,该事务对数据的更改会持久到数据库,且不会被回滚。
数据库事务在实现时会将一次事务的所有操作全部纳入到一个不可分割的执行单元,该执行单元的所有操作要么都成功,要么都失败,只要其中任一操作执行失败,都将导致整个事务的回滚。
3 分布式事务
在分布式系统中,事务的访问涉及的资源、参与计算的节点都部署在不同的节点上,这种情况下涉及到的事务称为分布式事务。
(1) 分布式事务涉及的场景
- 跨JVM进程产生分布式事务
典型的场景就是微服务架构:微服务之间通过远程调用完成事务操作。比如:订单微服务和库存微服务,下单的同时订单微服务请求库存微服务减少库存。
- 跨数据库实例产生分布式事务
单体系统访问多个数据库实例当单体系统需要访问多个数据库(实例)时就会产生分布式事务。比如:用户信息和订单信息分别在两个MySQL实例存储,用户管理系统删除用户信息,需要分别删除用户信息及用户的订单信息,由于数据分布在不同的数据实例,需要通过不同的数据库链接去操作数据,此时产生分布式事务。
- 多服务访问同一个数据库实例
订单微服务和库存微服务即使访问同一个数据库也会产生分布式事务,原因就是跨JVM进程,两个微服务持有了不同的数据库链接进行数据库操作,此时产生分布式事务。
(2)分布式事务解决方案
针对不同的分布式场景业界常见的解决方案有 2PC、3PC、TCC、可靠消息最终一致性、最大努力通知这几种。
强一致性实现
两阶段提交协议---2PC---解决分布式系统一致性问题的算法
在两阶段提交协议中,有两种角色:
协调者 coordinator:在系统中通常只有一个,负责协调决策
参与者 cohorts/participants:在系统中有多个,具备实现本地事务的能力
两阶段协议的流程可以描述如下:
阶段一,投票阶段
协调者向所有参与者发起询问,是否可以提交事务
每个参与者为参与事务做准备工作,如锁定资源、预先分配资源等,将结果记录日志
参与者将事务准备阶段的处理结果返回协调者,如果成功,则回应可以提交
阶段二,提交阶段协调者根据参与者返回的结果进行决策,如果全部返回成功则提交事务,如果有任何一个参与者返回失败,则回滚事务。
参与者收到协调者的通知后执行相应的操作,完成事务的最终提交或者回滚。
2PC做出如下假设:
1.由于在第一阶段需要预先分配或者锁定资源,导致在后续整个事务完成前资源都被占用,从而导致整体并发性能较低。
2.网络超时问题。在两个阶段中,都有可能发生网络超时。第一阶段,如果参与者返回结果超时,则协调者可以认为其失败,回滚事务;第二阶段,如果参与者返回最终提交/回滚的结果超时,则可以进行重试操作;或者协调者可以将其移出集群,这样最终数据仍旧是一致的;比较麻烦的是,在第二阶段,如果协调者不能将最终的决策结果发送给参与者,这样参与者则不知道如何进行下一步动作(决策信息不足),这样陷入了无法决策的尴尬场景。
为了解决两阶段提交中存在的上述问题,提出了三阶段提交协议,其三个阶段分别为:
- 投票阶段:协调者向参与者询问是否可以执行提交,参与者返回结果。
- 预提交阶段:如果所有参与者都返回成功,则协调者向所有参与者发出预提交的指令,参与者不进行真正的提交,但是锁定响应的资源,并返回预提交的结果。
- 提交阶段:如果所有参与者在预提交阶段都返回成功,则协调者发出最后的的提交指令,参与者执行最终的提交动作。
与两阶段提交不同的是,在投票阶段,参与者不会锁定资源,这样就避免了由于该阶段资源锁定导致的性能下降。在最终的提交阶段,如果出现超时问题,由于参与者在预提交阶段已经收到了成功指令,可以认为其他所有参与者也同意了这笔提交,则可以直接将状态修改为成功。