-
Notifications
You must be signed in to change notification settings - Fork 0
Description
事务的 ACID 特性
-
原子性(Atomicity):原子性是指事务包含的所有操作要么全部成功
-
一致性(Consistency):事务执行之前和执行之后都必须处于一致性状态
- 强一致性:当更新操作完成之后,任何一个后续进程或者线程的都能访问到最新更新过的值
- 弱一致性:系统不能保证后续访问返回更新的值,需要在一些条件满足之后,更新的值才能返回
- 最终一致性:弱一致性的特定形式,系统保证在没有后续更新的前提下,系统最终返回上一次更新操作的值
-
隔离性(Isolation): 多个并发事务之间要相互隔离,事务的隔离性数据库提供了多种隔离级别
- 读未提交(read uncommitted),会出现脏读、不可重复读、幻读
- 读提交(read committed),会出现不可重复读、幻读
- 可重复读(repeatable read),会出幻读
- 序列化(serializable),不会出现脏读、不可重复读、幻读,但是效率很慢
-
持久性(Durability): 事务一旦被提交了,那么对数据库中的数据的改变就是永久性的
CAP 理论
在分布式系统中**,一致性**、可用性和分区容错性,3 个要素最多只能同时满足两个,不可兼得。
- 一致性(Consistency):数据在多个副本之间是否能保证强一致性
- 可用性(Availability):分布式服务能一直保证可用状态,当用户发出一个请求后,服务能在有限时间内返回结果
- 分区容忍性(Partition Tolerance):在遇到任何网络分区故障的时候,仍然能够保证对外提供服务,除非是整个网络环境都发生了故障
AP(可用性 + 分区容忍性) = BASE
放弃C并不是完全不需要数据的一致性(如果是这样,数据就没有了意义),实际上是放弃强一致性,保留最终一致性
AC(可用性 + 一致性) = ACID
放弃P意味着放弃了系统的可扩展性,实际上变成了单点应用
CP(一致性 + 分区容忍性) = ?
请求都需要在Server之间强一致,而分区会导致同步时间无限延长,如此CP也是可以保证的,但是导致系统可用性降低,性能急剧下降
- 以上概念表达上仅供参考,并非十分准确,掺杂了个人理解和互联网上各种说法。
分布式系统中,最重要的是满足业务需求,而不是追求抽象绝对的系统特性。
BASE
可以通过放弃系统在每个时刻的强一致性来换取系统的可扩展性。核心思想:
- 基本可用(BasicallyAvailable):指分布式系统在出现故障时,允许损失部分的可用性来保证核心可用
- 软状态(SoftState):指允许分布式系统存在中间状态,该中间状态不会影响到系统的整体可用性
- 最终一致性(EventualConsistency):指分布式系统中的所有副本数据经过一定时间后,最终能够达到一致的状态
ACID是传统数据库常用的设计理念,追求强一致性模型。BASE支持的是大型分布式系统,提出通过牺牲强一致性获得高可用性。ACID和BASE代表了两种截然相反的设计哲学。
在分布式系统设计的场景中,系统组件对一致性要求是不同的,因此ACID和BASE又会结合使用。
分布式系统的BASE理论 http://www.hollischuang.com/archives/672
XA协议
XA 是 X/Open DTP组织(X/Open DTP Group)定义的两阶段提交协议。
X/Open DTP模型(1994)包括应用程序(AP)、事务管理器(TM)、资源管理器(RM)、通信资源管理器(CRM)四部分。
通常**事务管理器(TM)**是交易中间件,**资源管理器(RM)**是数据库,通信资源管理器(CRM)是消息中间件。
XA是一个协议,实现的关键是二阶段提交(2PC),其有个致命的缺点,那就是性能不理想,无法满足高并发场景。
2PC(Two-Phase Commit)
2PC 主要保证了分布式事务的原子性:即所有结点要么全做要么全不做
准备阶段(Prepare)
事务协调者(事务管理器)给每个参与者(资源管理器)发送prepare消息,每个参与者要么直接返回失败,要么在本地执行事务但不提交,并将Undo信息和Redo信息写入日志,到达一种“万事俱备,只欠东风”的状态。
提交(Commit) / 回滚(Rollback)
如果协调者收到了参与者的失败消息,直接给每个参与者发送回滚(Rollback)消息;否则,发送提交(Commit)消息;参与者根据协调者的指令执行提交或者回滚操作,释放所有事务处理过程中使用的锁资源。
3PC
3PC 在 2PC 的基础增加以下两点:
- 在协调者和参与者中引入了超时机制,减少阻塞
- 将2PC的第一个阶段分成了两个阶段,保证了在最后提交阶段之前各参与节点的状态是一致的
CanCommit阶段
协调者想参与者发送提交询问请求,如果可以提交就返回Yes,否者返回No,询问阶段。该阶段和 2PC的准备阶段(Prepare)很像但是不记录undo和redo日志。
PreCommit阶段
可以提交的话记录 undo和redo日志。
DoCommit阶段
通知各个参与者对事务进行提交。
在任意阶段如果请求超时,则发送回滚信号。
2PC 与 3PC 总结
优点
- 都是把 比较耗时、大概率会出错 的操作提前进行预演,在最开始进行执行,例如2PC的 Prepare阶段、3PC的 CanCommit阶段; 把 执行比较快、出错概率比较小 的情况放到最后,最后提交commit 阶段;提升了整个事务的执行成功率
缺点与不足
- 2PC 和 3PC 都不能完全保证事务最后一定是一致的,只能提升成功的概率
- Google Chubby的作者Mike Burrows说过:世上只有一种一致性算法,那就是Paxos,所有其他一致性算法都是Paxos算法的不完整版
2PC和3PC的详细过程请参见:
关于分布式事务、两阶段提交协议、三阶提交协议
分布式协议之两阶段提交协议(2PC)和改进三阶段提交协议(3PC)
消息队列 异步确保型事务
核心思想是将需要分布式处理的任务通过消息或者日志的方式来异步执行,消息或日志可以存到本地文件、数据库或消息队列,再通过业务规则进行失败重试,它要求各服务的接口是幂等的。
假如有一个场景为:有用户表user 和交易表transaction,用户表存储用户信息、总销售额和总购买额,交易表存储每一笔交易的流水号、买家信息、卖家信息和交易金额。如果产生了一笔交易,需要在交易表增加记录,同时还要修改用户表的金额。
解决方法是将更新交易表记录和用户表更新消息放在一个本地事务来完成。这个方案的核心在于需要保证第二阶段(用户表更新)的重试是幂等执行
- 假如是根据用户ID进行更新,则多次执行产生的结果是一样的,即符合幂等性
- 假如多个不同的消息对同一个用户ID进行更新,可以对消息加上一个全局自增的ID(分布式环境下的时序),只允许ID大的消息覆盖ID小的消息
失败后重试,这是一种补偿机制,它是能保证系统最终一致的关键流程。
TCC 补偿型事务
- Try:尝试执行业务。
- 完成所有业务检查(一致性)
- 预留必须业务资源(准隔离性)
- Confirm:确认执行业务。
- 真正执行业务
- 不做任何业务检查
- 只使用Try阶段预留的业务资源
- 要满足幂等性
- Cancel:异常取消执行业务
- 释放Try阶段预留的业务资源
- 要满足幂等性
优缺点
- 与 2PC 相比,位于业务层而非资源层
- 很多场景下幂等要求也不容易实现
- 预留资源成本较高,比如可能会引入锁,对性能和可扩展性有害
一个支付项目的例子
支付系统接收到会员的支付请求后,需要扣减会员账户余额、增加会员积分(暂时假设需要同步实现)增加商户账户余额。再假设:会员系统、商户系统、积分系统是独立的三个子系统,无法通过传统的事务方式进行处理。
- TRYING阶段:我们需要做的就是会员资金账户的资金预留,即:冻结会员账户的金额(订单金额)
- CONFIRMING阶段:我们需要做的就是会员积分账户增加积分余额,商户账户增加账户余额
- CANCELING阶段:该阶段需要执行的就是解冻释放我们扣减的会员余额
以上所有的操作需要满足幂等性,幂等性的实现方式可以是:
- 通过唯一键值做处理,即每次调用的时候传入唯一键值,通过唯一键值判断业务是否被操作,如果已被操作,则不再重复操作
- 通过状态机处理,给业务数据设置状态,通过业务状态判断是否需要重复执行
定期校对型
一般通过定时任务跑批,查询出数据不一致的情况,进行修复
最大努力型
- 业务发起方在完成业务后,向业务被动方发送通知消息,消息允许丢失
- 发起方按照设定的时间解题通知被动方,通知失败后按照规则重复通知,直到成功或者到达一定的次数
- 发起方提供接口供被动方进行数据校对
常用分布式事务解决方案总结
- 刚性事务
- 全局事务(标准分布式事务)
- 柔性事务
- 可靠消息最终一致(异步确保型)
- TTC(两阶段、补偿型)
- 最大努力通知(费可靠消息、定期校对)
- 纯补偿型
拓展阅读
分布式事务的典型处理方式:2PC、TCC、异步确保和最大努力型
常用的分布式事务解决方案介绍有多少种?
分布式系统的一致性探讨
常用的分布式事务解决方案介绍
程立谈大规模SOA系统