分布式数据库事务

一、背景

当我们的单个数据库的性能产生瓶颈的时候,我们可能会对数据库进行分区。 这时候事务不能只依靠本地数据库对事务支持来实现了。

二、集中实现方案

2.1 两阶段提交(2PC)

假设事务在a,b两个数据库上。 那现在要对这两个数据库实现事务支持, 就是分别操作a,b上的事务, 由一个中间件收集a,b操作的结果。 若都成功了, 就commit, 否则就回滚。

优点:强一致性。

缺点:

(1) 如commit到数据库过程中出了问题, 导致事务可能不会结束。

(2) 性能差。涉及多次节点间的网络通信, 通信时间过长, 导致事务时间过长, 锁定的资源也变长了, 造成资源等待时间也过长。

2.2 补偿事务(TCC)

TCC 其实就是采用的补偿机制,其核心思想是:针对每个操作,都要注册一个与其对应的确认和补偿(撤销)操作。它分为三个阶段:

(1) Try 阶段主要是对业务系统做检测及资源预留

(2) Confirm 阶段主要是对业务系统做确认提交,Try阶段执行成功并开始执行 Confirm阶段时,默认 Confirm阶段是不会出错的。即:只要Try成功,Confirm一定成功。

(3) Cancel 阶段主要是在业务执行错误,需要回滚的状态下执行的业务取消,预留资源释放。

优点:解决事务过长问题。

缺点:需要编写额外补偿代码, 造成代码庞大, 难以维护。

2.3 消息队列

RocketMQ第一阶段发送Prepared消息时,会拿到消息的地址,第二阶段执行本地事物,第三阶段通过第一阶段拿到的地址去访问消息,并修改状态。细心的读者可能又发现问题了,如果确认消息发送失败了怎么办?RocketMQ会定期扫描消息集群中的事物消息,这时候发现了Prepared消息,它会向消息发送者确认,Bob的钱到底是减了还是没减呢?如果减了是回滚还是继续发送确认消息呢?RocketMQ会根据发送端设置的策略来决定是回滚还是继续发送确认消息。这样就保证了消息发送与本地事务同时成功或同时失败。

举个例子: 去面馆吃面。 先去收银台付钱, 收银台会给你一个小票, 并且通知厨房做面。 厨房做面失败, 会有大堂经理通知你失败, 并退钱给你。 或者成功了,服务员把你端给你, 然后收回你的小票。消息队列处理事务大概是这样的过程。 这里的发票相当于消息队列中的消息。 付钱和收到做好的面可以看做1个事务要做的两件事。 这里还有一些问题, 首先收银员收了钱却忘了给你小票呢? 这种情况先开个准备付款小票, 当收到钱后,再确认已经付款。 如果忘了给小票肯定还是有个准备付款小票以及查询付款记录就知道是不是付款了。消息队列还会重复消费, 还要注意查重。

2.4 当做一个任务来处理

一个任务处理过错可能会有很多步骤, 一般程序做完一步就会写入日志。 程序处理任务时崩溃时候, 我们可以通过日志判断任务处理情况, 然后就可以准确修复了。 我们这里可以这样每处理完事务中一条sql, 就把一个唯一事务id作为记录插入一个事务登记表中相当于日志。 用一个模块去扫描这些表就可以找出事务有问题的表然后去修复。这个方案想对实现起来简单。

优点: 由于把事务拆成小的事务, 性能更高。 

缺点:补偿方案比较麻烦。

参考:  https://blog.csdn.net/u011393781/article/details/52754515

参考:https://www.cnblogs.com/savorboard/p/distributed-system-transaction-consistency.html

展开阅读全文

没有更多推荐了,返回首页