代码改变世界

说说分布式事务

2016-01-28 15:18 轩脉刃 阅读(...) 评论(...) 编辑 收藏

分布式事务

分布式事务说的就是一个事务的两个或者多个操作不是在一个数据库中进行的,而是在多个数据库中执行。
这个时候,如何保证事务操作的原子性和一致性?

举个支付的例子,支付进行买东西。事务由两个行为组成,我的购买商品数据表数据+1,支付金额表数据-1。
如果这两个都是在同一库中,没啥问题。

try {
    事务开始
    购买商品数据表数据+1
    支付金额表数据-1
    事务结束
} catch 事务失败 {
    事务回滚
}

但是这两个表是在两个库中,那么就用到二阶段提交了

二阶段提交

二阶段提交(2PC)增加了事务处理器和事务执行者的角色。由事务处理器来进行整个事务的处理。主要流程如下面的图

两阶段提交协议

prepare

当开始事务调用的时候,事务处理器向事务执行者(有可能是数据库本身支持)发出命令,事务执行者进行prepare操作。

当所有事务执行者都完成了prepare操作,就进行下一步行为。

如果有一个事务执行者在执行prepare的时候失败了,那么通知事务处理器,事务处理器再通知所有的事务执行者执行回滚操作。

commit

当所有事务执行者都prepare成功以后,事务处理器会再次发送commit请求给事务执行者,所有事务执行者进行commit处理。

当所有commit处理都成功了,那么事务执行结束。

如果有一个事务执行者的commit处理不成功,这个时候就要通知事务处理器,事务处理器通知所有的事务执行者执行回滚(abort)操作。

但是两阶段提交的诟病就是在于性能问题。比如由于执行链比较长,锁定资源的时间也变长了。所以在高性能的系统中都会避免使用二阶段提交。

使用消息系统避免分布式事务

这种方法是文章如何用消息系统避免分布式事务?中提到的方法。

首先这种方法必须在产品上有所妥协。比如支付过程,在支付操作之后,并不是立即返回告知用户你是否成功,并且扣除金额(当然如果消息队列通畅的情况下看起来是立即返回的)。

而是在支付的过程中,先恭喜你获取物品成功,然后获取物品成功后通知消息队列,由消息队列再进行扣除金额的操作。

当然消息队列有可能操作失败,操作失败以后由于有凭证,可以进行重试操作。

最终支付成功后,再进行消息确认,从而保证消息一致性。

参考文章

如何用消息系统避免分布式事务?