首页 存档 技术 查看内容

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

2018-3-30 13:00 |来自: 互联网 262 0

摘要: (点击上方公众号,可快速关注我们) 来源:伯乐在线 - 占利军 链接:http://blog.jobbole.com/89140/ 前阵子从支付宝转账1万块钱到余额宝,这是日常生活的一件普通小事,但作为互联网研发人员的职业病,我就思考支 ...

(点击上方公众号,可快速关注我们)


来源:伯乐在线 - 占利军

链接:http://blog.jobbole.com/89140/

前阵子从支付宝转账1万块钱到余额宝,这是日常生活的一件普通小事,但作为互联网研发人员的职业病,我就思考支付宝扣除1万之后,如果系统挂掉怎么办,这时余额宝账户并没有增加1万,数据就会出现不一致状况了。

上述场景在各个类型的系统中都能找到相似影子,比如在电商系统中,当有用户下单后,除了在订单表插入一条记录外,对应商品表的这个商品数量必须减1吧,怎么保证?!在搜索广告系统中,当用户点击某广告后,除了在点击事件表中增加一条记录外,还得去商家账户表中找到这个商家并扣除广告费吧,怎么保证?!等等,相信大家或多或多少都能碰到相似情景。

本质上问题可以抽象为:当一个表数据更新后,怎么保证另一个表的数据也必须要更新成功。

1 本地事务

还是以支付宝转账余额宝为例,假设有

  • 支付宝账户表:A(id,userId,amount)

  • 余额宝账户表:B(id,userId,amount)

  • 用户的userId=1;

从支付宝转账1万块钱到余额宝的动作分为两步:

  • 1)支付宝表扣除1万:update A set amount=amount-10000 where userId=1;

  • 2)余额宝表增加1万:update B set amount=amount 10000 where userId=1;

如何确保支付宝余额宝收支平衡呢?

有人说这个很简单嘛,可以用事务解决。

Begin transaction

update A set amount=amount-10000 where userId=1;

update B set amount=amount 10000 where userId=1;

End transaction

commit;

非常正确,如果你使用spring的话一个注解就能搞定上述事务功能。

@Transactional(rollbackFor=Exception.class)

public void update() {

updateATable();

//更新A表

updateBTable();

//更新B表

}

如果系统规模较小,数据表都在一个数据库实例上,上述本地事务方式可以很好地运行,但是如果系统规模较大,比如支付宝账户表和余额宝账户表显然不会在同一个数据库实例上,他们往往分布在不同的物理节点上,这时本地事务已经失去用武之地。

既然本地事务失效,分布式事务自然就登上舞台。

2 分布式事务两阶段提交协议

两阶段提交协议(Two-phase Commit,2PC)经常被用来实现分布式事务。一般分为协调器C和若干事务执行者Si两种角色,这里的事务执行者就是具体的数据库,协调器可以和事务执行器在一台机器上。

  • 1) 我们的应用程序(client)发起一个开始请求到TC;

  • 2) TC先将

声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

相关分类

返回顶部