分布式八大坑

分布式就是魔鬼啊!

张大胖最近十分感慨,他所在的公司原来有个电商系统,后来随着用户量越来越大,对系统的可用性要求越来越高。 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帝国之宫廷内斗》吧!”

来源:码农翻身

分布式的事务该怎么做?相关推荐

  1. SAP事务码f-02做账界面显示“页数”字段

    事务码 f-02 做账界面,没有显示页数. 用户账号的参数添加 CSF (Country-Specific Fields)参数,参数值为 CN(伟大的China) 再次来到 f-02 的界面,显示了页 ...

  2. CSDN开发者周刊 TDengine:专为物联网订制的大数据平台 YugaByte DB:高性能的分布式ACID事务数据库

    CSDN开发者周刊:   TDengine:专为物联网订制的大数据平台 YugaByte DB:高性能的分布式ACID事务数据库 CSDN开发者周刊:只为传递"有趣/有用"的开发者 ...

  3. 分布式交易事务_交易基础和分布式交易

    当客户在网上商店购买商品时,您希望您的订单能够被快速处理和交付. 作为银行客户,您要确保转账期间钱不会神秘地消失. 在企业应用程序中,经典事务保证了诸如一致性和与其他事务的隔离之类的质量. 分布式事务 ...

  4. 你真的很熟分布式和事务吗?

    微吐槽 hello,world. 不想了,我等码农,还是看看怎么来处理分布式系统中的事务这个老大难吧! 本文略长,读者需要有一定耐心,如果你是高级码农或者架构师级别,你可以跳过. 本文注重实战或者实现 ...

  5. 面试精讲之面试考点及大厂真题 - 分布式专栏 16 数据库如何做分库分表,读写分离

    16 数据库如何做分库分表,读写分离 宝剑锋从磨砺出,梅花香自苦寒来. --佚名 引言 2016年第一次接触分布式微服务项目后,我在简历上写了我使用了微服务.分库分表技术,那么问题来了,面试官说接下来 ...

  6. 当数据库遇到分布式,你会怎么做?

    数据库通常有着完善的事务支持,但是局限于单机的存储和性能,于是就出现了各种分布式解决方案.最近读了<Designing Data-Intensive Applications>这本书,所以 ...

  7. 数据库怎么保证(分布式)事务一致性

    浅谈事务与一致性问题 原文地址 https://www.jianshu.com/p/f0a1b00a6002 在高并发场景下,分布式储存和处理已经是常用手段.但分布式的结构势必会带来"不一致 ...

  8. 分布式柔性事务详解--基于事务型MQ

    一.概述 咱们今天聊聊分布式事务系列中的最后一个方案:最大努力通知事务.最大努力通知事务的主流实现仍是基于MQ来进行事务控制.最大努力通知事务和事务消息都是通知型事务,主要适用于那些需要异步更新数据, ...

  9. 分布式 | dble 启动的时候做了什么之配置检测

    作者:吴金玲 爱可生 dble 项目团队成员,主要负责 dble 相关的日常测试工作,擅长对 dble 中出现的问题进行排查.热爱测试工作,余生欲将测试工作进行到底. 本文来源:原创投稿 *爱可生开源 ...

最新文章

  1. Kotlin基本语法和使用
  2. 使用vb6绿色版做一个简易图片浏览器
  3. 使VM的虚拟机内存超越物理内存的方法
  4. Java and Jakarta - Hybris
  5. 八种ADSL接入情况中断流现象分析
  6. stm32 SPI架构
  7. 正则表达式实现身份证信息验证
  8. C#多线程学习(三) 生产者和消费者 (转载系列)——继续搜索引擎研究
  9. 微波网络中插入相移插入衰减和输入驻波比
  10. linux搭建nacos集群
  11. mongodb的安装和使用
  12. PHP基础教程(第4版)电子书pdf下载
  13. android手机账号什么意思,苹果手机怎么改id账号 id账号是什么
  14. Linux下SD卡格式化,为SD卡分区
  15. 文件夹怎么加密 怎么给文件夹加密
  16. CAD批量打图精灵入门教程--CAD批量打印、CAD批量转PDF
  17. ZOJ 3789 Gears
  18. kali 运行wifite时遇到的问题及解决办法
  19. Linux C 遍历目录下的所有文件
  20. 404未找到是什么意思_http404未找到怎么解决,404 未找到常见问题汇总

热门文章

  1. 【转】使用python3的typing模块提高代码健壮性
  2. MySQL数据库Keepalived双主
  3. 第6周第4课:复习及扩展知识
  4. OAF在打开的新页面中添加按钮,功能是关闭当前页面
  5. 2016年,新的开始
  6. Servlet/jsp和Action/jsp传值
  7. [题解]CQOI2012 T2 组装 assemble
  8. 【VS2005】error LNK2001: unresolved external symbol _main 正确解决办法
  9. RTSP协议转换RTMP直播协议
  10. c语言程序-hello world-运行原理简介