分布式的事务该怎么做?(文末问卷抽奖)

2018 年 12 月 10 日 码农翻身


分布式八大坑


分布式就是魔鬼啊! 


张大胖最近十分感慨,他所在的公司原来有个电商系统,后来随着用户量越来越大,对系统的可用性要求越来越高。 CTO要求把系统进行拆分, 从一个单体的应用,拆分成微服务组成的应用。 


微服务听起来很美好,但是其中的苦只有做过的人才知道。  


在原来的单体应用中,订单模块想要调用库存和支付,只要调用相关的类或者接口就可以了,只有一个数据库,轻轻松松就可以把所有操作放到一个事务当中,保证不会出现扣了库存但是支付失败的情况。 


 (单体应用) 

现在好了,系统成了分布式,原来的进程间调用变成了跨越网络的HTTP调用,这数据库也从单个数据库变成了多个独立的数据库,原来的事务肯定是不起作用了! 



大神Bill告诉张大胖分布式有八个大坑, 千万别跳到坑里去:  


当你在构建一个分布式系统的时候,可能会不由自主地做一些假设,这些假设从长期来看,都是错误的,都会导致大麻烦: 


1. 网络是可靠的 

2. (调用)没有延迟 

3.  无限的带宽 

4. 网络是安全的 

5. (系统)拓扑结构不会改变 

6. 有个管理员在管理这个系统 

7. (数据)传输代价为零 

8. 网络是同质的(同类的)  


这第一条就很要命,网络是不可靠的, 网络调用失败的可能性是非常高的,很有可能出现扣减了库存,但是没有支付的情况。 


分布式的事务


怎么样让扣减库存和支付服务能在一个类似数据库事务中完成,要么都做,要么都不做呢? 张大胖觉得十分头疼。 


张大胖首先想到了两阶段的提交(2PC),但是2PC是针对底层的数据资源层实现的,现在要做的是业务层的事情, 况且这2PC也很不好用啊。 


(码农翻身注: 2PC的故事参见《Java帝国之宫廷内斗》) 


他觉得必须要有一个协调人居中协调各个微服务,让他们处于一个“事务”中, 可是这协调者该如何实现? 


Bill 递给他一篇文章:“你要实现的就是分布式事务了!看看这篇文章吧!”  


张大胖接过打印的文章,标题是:《Distributed Atomic Transactions over RESTful Services》 ,他的头嗡地一声就变大了,哀叹道:“英文的啊,你还是给我讲讲吧!” 


“英文很重要啊,大胖同学!” Bill说道,“其实这个分布式事务的原理很简单,它的精华就是冻结资源幂等性。”

 (此处应该插入一个英语广告,哈哈。) 


张大胖说:“这幂等性我知道,就是一个操作不管是执行一千次,一万次,效果和执行一次是一样的。 这冻结资源是怎么回事?” 


“拿咱们的系统举个例子吧,订单服务要调用库存服务扣减库存(假设数量为2),还要调用支付服务从用户余额扣钱(假设为100), 那订单服务第一步就告诉库存服务,给我冻结2个库存; 告诉支付服务,给我冻结100块钱。在这一步,两个服务要做业务检查,看看库存余额够不够,如果足够,就冻结他们,防止其他调用也进行了扣减操作,导致本次调用余额不足。 这一步,我们称之为尝试(Try)。 ” 


 (注: 这里也可以对库存数量和用户余额做扣减)  


库存服务和支付服务操作的都是自己的表,冻结操作可以放到一个本地事务中,保证原子性。 


 “明白, 接下来呢?” 张大胖问道。 


 “这一步如果成功完成,订单服务就可以进入第二步,告诉这两个服务真正地执行扣减操作,这一步叫做Confirm。” 


 (注:如果在第一步已经做了扣减,这里只需要修改相关状态即可,大家可自行脑补。 ) 


“慢着,如果调用支付服务进行Confirm时出错怎么办? ” 张大胖问道。


 “很简单,那就告诉库存服务和订单服务,都进行Cancel操作, 把冻结的数量进行恢复。” 


Bill说道。 “我们把这套机制叫做 Try - Confirm -Cancel,简称TCC。对于每个每个微服务来讲,都要提供try , confirm , cancel这三个接口。” Bill接着说,“另外每个微服务也得有一个专门用来管理TCC的组件。” 



异常场景


张大胖心想,你说得简单,这都是所谓Happy Path , 在分布式环境中出错是必然的,他很快找到了第一个场景: 


场景1 : 库存服务的Try操作完成, 支付服务的Try操作没有完成, 怎么办?  


Bill说:“这很好处理,订单服务可以尝试去调用库存的Cancel操作(这应该是个幂等操作,可以多次调用),把冻结的库存释放。” 


张大胖说:“那如果出现网络问题,订单服务无法联系库存服务了呢?” 


“不用担心,库存服务的TCC组件能够发现冻结的时间已经超时,会自动把冻结的库存给释放。”  


场景2 : 两个微服务的Try操作都完成, 然后发生网络故障,导致两个Confirm都无法进行 


Bill说: “和第一种情况一下,TCC组件会发现超时,释放冻结的资源, 当然,冻结的这部分资源在释放前的一段时间内不可以被使用。” 


“可是,如果库存服务所在的机器已经挂掉了呢?怎么计算超时?” 张大胖问道。 


“这是个好问题,所以TCC系统必须得记录日志,把那些没有完成的事情记录下来,持久化到硬盘上。这样下次重启就可以接着执行了。” 


场景3 : Try操作都已完成,资源已经冻结,在第三步中库存服务Confirm成功,库存做了扣减, 但是支付服务挂掉了,余额还处于冻结状态, 怎么办? 


Bill 说道:“那可以多尝试几次, 让支付服务做Confirm操作(很明显,这个Confirm操作必须得是一个幂等操作才行)。如果实在是无法成功,那就可以让库存服务做Cancel操作。 如果还是不行,只有让人工介入了。” 


怪不得Bill一直在强调幂等性,原来真正的作用是这样啊。


转向BASE?

  

张大胖想了想,似乎各种情况都能覆盖了, 但是还有实现层面的大问题: 


(1) 就是对于try (冻结资源), confrim , cancel(恢复资源)这样的操作都需要程序员去写代码实现。 


比如对于支付服务, 至少的实现三个方法: 


tryPayment(......) 

confirmPayment(......) 

cancelPayment(......)  


这样TCC框架才可以去调用。  


(2) 还得自己搞个TCC框架。 


Bill 笑道: “那没办法,分布式就是这么烦人。TCC框架倒是有一些现成的,比如Atomikos,tcc-transaction,Hmily等, 但是那些try,confrim, cancel是业务方法,程序员必须得写, 跑不掉的。”  


“就没有别的办法了吗?”


“有啊,也可以尝试下另外一个最终一致性的模型,叫做BASE。”  Bill随手又递过来一篇论文,名字是《BASE: An Acid Alternative》  


“有没有搞错 ! 又是英文的!”  


“你要是不想看英文的,就去看看老刘写的《Java帝国之宫廷内斗》吧!”


往期 精彩回顾
Java帝国之宫廷内斗
MySQL:缓存算什么东西?!

Redis:MySQL算老几?

后端风云

别吵吵,分布式锁也是锁

我也是一个线程,为什么每天累得像狗一样?

聊聊微服务的隔离和熔断


帮神策数据做个调查“男程序员之理想中的另一半”, 填写问券就可能获得价值299的双肩包(抽奖,一共10个),程序员必备之良品。



切记, 最后一个问题,一定要填写自己的联系方式,否则抽奖就没你的份儿了


ps: 这个调查问卷是用问卷星做的,填写完以后,问卷星会显示讨厌的抽奖/广告,直接关闭即可。双肩包抽奖是神策数据工作人员手动做的,和问卷星显示的抽奖没有关系。


长按二维码或者点击阅读原文,参与抽奖。

登录查看更多
0

相关内容

【北京大学】面向5G的命名数据网络物联网研究综述
专知会员服务
36+阅读 · 2020年4月26日
算法与数据结构Python,369页pdf
专知会员服务
161+阅读 · 2020年3月4日
新时期我国信息技术产业的发展
专知会员服务
69+阅读 · 2020年1月18日
【干货】大数据入门指南:Hadoop、Hive、Spark、 Storm等
专知会员服务
95+阅读 · 2019年12月4日
资源|Blockchain区块链中文资源阅读列表
专知会员服务
43+阅读 · 2019年11月20日
知识图谱本体结构构建论文合集
专知会员服务
106+阅读 · 2019年10月9日
在K8S上运行Kafka合适吗?会遇到哪些陷阱?
DBAplus社群
9+阅读 · 2019年9月4日
每个架构师都应该培养业务思维
InfoQ
3+阅读 · 2019年4月21日
个人吐血整理的系统设计资料大全
九章算法
86+阅读 · 2019年3月6日
我在知识星球这一年
码农翻身
10+阅读 · 2019年2月28日
蚂蚁金服微服务实践(附演讲PPT)
开源中国
18+阅读 · 2018年12月21日
可能是讲分布式系统最到位的一篇文章
InfoQ
8+阅读 · 2018年11月19日
为什么分布式一定要有消息队列?
互联网架构师
4+阅读 · 2018年7月5日
【区块链】区块链是什么?20问:读懂区块链
产业智能官
8+阅读 · 2018年1月10日
一个人的企业安全建设之路
FreeBuf
5+阅读 · 2017年7月7日
Arxiv
35+阅读 · 2019年11月7日
Monocular Plan View Networks for Autonomous Driving
Arxiv
6+阅读 · 2019年5月16日
Arxiv
15+阅读 · 2019年4月4日
Simplifying Graph Convolutional Networks
Arxiv
12+阅读 · 2019年2月19日
Arxiv
23+阅读 · 2018年10月1日
VIP会员
相关VIP内容
相关资讯
在K8S上运行Kafka合适吗?会遇到哪些陷阱?
DBAplus社群
9+阅读 · 2019年9月4日
每个架构师都应该培养业务思维
InfoQ
3+阅读 · 2019年4月21日
个人吐血整理的系统设计资料大全
九章算法
86+阅读 · 2019年3月6日
我在知识星球这一年
码农翻身
10+阅读 · 2019年2月28日
蚂蚁金服微服务实践(附演讲PPT)
开源中国
18+阅读 · 2018年12月21日
可能是讲分布式系统最到位的一篇文章
InfoQ
8+阅读 · 2018年11月19日
为什么分布式一定要有消息队列?
互联网架构师
4+阅读 · 2018年7月5日
【区块链】区块链是什么?20问:读懂区块链
产业智能官
8+阅读 · 2018年1月10日
一个人的企业安全建设之路
FreeBuf
5+阅读 · 2017年7月7日
Top
微信扫码咨询专知VIP会员