分布式事务浅析
之前看《数据库系统实现》中有讲一些分布式事务,稍微了解了一下,这次再好好总结一下。文中有借用了网上的一些图。有侵权联系删除。
数据服务性能的提升主要依靠两种方式
- 数据分区(不同数据存在不同节点)
- 数据备份(多节点拷贝,相同数据存放多个节点)
- Master-Slave。读写请求都由Master负责。写请求写到Master上后,由Master同步到Slave上。问题是:单点崩溃无法提供写服务
- Master-Master。所有节点可以提供写服务。问题:数据一致性,以及多节点数据冲突
CAP理论
分布式领域有CAP理论,三者无法都同时达到最优,顾此失彼
- 一致性
- 强一致性
- 弱一致性(包括最终一致性)
- 可用性:在有节点宕机之后,仍然能够正确提供服务,好的响应性能。
- 分区容忍性:分区之后,某些数据被分在一个单独的节点,因为各种原因导致这个节点无法访问,这是无法容忍的。解决方案就是备份节点。但是备份节点多了就会带来一致性的问题,同时写的时候要写多个节点,也会带来可用性的问题。
Base理论
即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。
- 基本可用:牺牲部分的可用性,响应时间可适当变长
- 软状态:允许数据存在中间状态,但是不会影响系统整体可用性
- 最终一致性:经过一段时间同步,数据能够达到一致性
两阶段提交
- 1.协调者:发送消息让所有节点准备提交
- 节点:收到消息执行事务并写好日志,回应给协调者成功或失败
- 2.协调者:当所有节点都回复成功时,事务提交;只要有一个没有回复成功,回滚
- 节点:收到协调者的回应后,提交事务
问题主要有:
- 同步阻塞:如果协调者没回应,会一直阻塞等待
- 单点故障:协调者在第二阶段故障,所有节点需要等待
- 死锁:两个节点互相持有资源
- 数据不一致:如果协调者在发送“提交事务信号时”宕机,一部分提交,一部分没提交。出现数据不一致问题
三阶段提交
主要解决了单点故障和阻塞的问题,如果第一阶段所有的结点返回成功,那么有理由相信成功提交的概率很大
- 1.协调者:发送消息给所有节点
- 节点:如果认为当前自己可以完整执行事务,回复成功
- 2.协调者:如果所有的节点都回复成功,通知所有节点进入预提交
- 节点:收到消息执行事务并写好日志,回应给协调者成功或失败
- 3.协调者:当所有节点都回复成功时,事务提交;只要有一个没有回复成功,回滚
- 节点:收到协调者的回应后,提交事务;若超时未收到消息,默认提交成功(默认成功提交的几率很大)
TCC
是应用层的一种补偿方法,需要代码实现。
- try:对业务系统做检测和预留
- confirm:执行业务流程,一般认为try成功,confirm一定成功
- cancel:事务遇到错误的回滚
举个例子,假入 Bob 要向 Smith 转账,思路大概是:
我们有一个本地方法,里面依次调用
- 首先在 Try 阶段,要先调用远程接口把 Smith 和 Bob 的钱给冻结起来。
- 在 Confirm 阶段,执行远程调用的转账的操作,转账成功进行解冻。
- 如果第2步执行成功,那么转账成功,如果第二步执行失败,则调用远程冻结接口对应的解冻方法 (Cancel)。
消息队列传递
将分布式事务分解成多个本地事务。具体做法:
- 本地事务执行前,准备消息。
- 执行完成,发送消息,否则取消消息。如果消息发送失败会尝试重新发送
- 远端接受消息,并执行。
问题:
- 重复消息的问题:在消息消费方检查是否有一个同样的消息,如果有就抛弃
- 消息发送失败:消费方提供一个check接口,接受到就返回确认