一次给女朋友转账引发我对分布式事务的思考

  • 时间:
  • 浏览:31
  • 来源:古韵博客 - 专注共享卢松博客资源

1、因为分析“第1步”刚执行完,系统因为分析一种生活因为分析宕机了,那会因为分析A银行账户扣款了,但会 写入消息队列失败,无法进行B银行接口调用,从而因为分析数据不一致。

2、因为分析B银行在执行“第5步”时因为分析校验失败而未能成功转账,在回调A银行接口通知回滚时网络异常因为分析宕机,会因为分析A银行转账无法完成回滚,从而因为分析数据不一致。

本文在另一方技术博客不同步发布,详情可用力戳

亦可扫描屏幕右侧二维码关注另一方公众号,公众号内有另一方联系法律法律依据,等你来撩...

  还记得刚毕业那年,带着满腔的热血就去到了一家互联网公司,领导给我的第有有一一个任务只是在列表上增加有有一一个修改数据的功能。这能难倒我?我分分钟让他搞出来!不只是在列表上增加了有有一一个“修改”按钮,点击按钮弹出框修改后保存就好了么。然而一切不像我要 象的这样顺利,点击保存并刷新列表后,页面上的数据还是显示的修改事先的内容,像这样修改成功一样!过一会儿再刷新列表,数据就能正常显示了!测试多次事先也有原先!没见过哪些地方大场面的我后后后后刚开始英文一阵一阵慌了,是我哪里写得不对么?最终,我不得不求助组内经验比较充沛的前辈!他深吸了一口气告诉是我不好:“毕竟是刚毕业的小伙子啊!我来跟你讲讲因为分析吧!亲们儿的数据库是做了读写分离的,帕累托图读库与写库在不同的网络分区。你的数据更新到了写库,而读数据的事先是从读库读取的。更新到写库的数据同步到读库是有一定的延迟的,也只是说读库与写库会有短暂的数据不一致”! “原先不必体验不好么?为哪些地方只有做到写入的数据立马能读出来?原先一些功能该为何在么在实现呢?” 面对我的一堆现象,同事一些不耐烦的说:“听说过CAP理论吗?你先另一方去了解一下吧”!是我后后后后刚开始英文查阅各种资料去了解一些陌生的词身旁的秘密!

   同样的,亲们儿可不都时会 在B银行系统中时要增加有有一一个转账日志表,因为分析叫转账流水表,B银行每次接收到转账请求,在对账户进行操作的事先一块儿往转账日志表中插入一条转账日志记录,同样这有有一一个操作也时只是原子的!在接收到转账请求后,首先根据唯一转账流水Id在日志表中查找判断该转账是是不因为分析外理过,因为分析未外理过则进行外理,但会 直接回调返回! 最终的架构图如下:

  

  

   本地事务讲到了一致性,分布式事务不可外理的面临着一致性的现象!回到最后后后后刚开始英文跨行转账的例子,因为分析A银行用户向B银行用户转账,正常流程应该是:

   在亲们儿还在“牙牙学语”的事先,老师老要会通过转账的栗子来跟亲们儿讲解事务,但跟这里场景不一样的是,老师讲的是本地事务,而这顶端对的是分布式事务!亲们儿先来简单回顾一下本地事务!

   为何在么在从我卡里扣钱这样这样来越快,而对方却要几秒都时会 到账?但会 转账失败后,扣除的钱还能及时的返还到我的卡里?万一钱返还失败为何在么在办?又因为分析我转一次钱,对方却收到了两次转账的申请又该如何?带着哪些地方地方现象,我脑海中浮现出“事务”二字!

   事先都因为分析从我卡里扣过钱了,现在却提示我转账失败,银行会不必把我的钱给吞了?转账失败的钱还能退换给我吗?正在我紧张、焦虑、坐立不安之时又收到一条app冲正的消息,事先转账失败的钱因为分析撤销给我了,看来我多虑了……这也证明咱平安银行的app还是比较安全靠谱的!

  

   在正常情況对一致性要求不高的场景,原先的设计是可不都时会 满足需求的。但会 像银行原先的系统,因为分析原先实现共要早就破产了吧。亲们儿先看看原先的设计最主要的现象:

   分布式事务只是在分布式的场景下,时要满足事务的需求!上篇文章亲们儿聊过了消息顶端件,那这篇文章亲们儿要聊的是分布式事务,把两者一结合,便有了基于消息顶端件的分布式事务外理方案!不管是本地事务,还是分布式事务,也有为了外理数据的一致性现象!一致性一些词咱们前面多次提及!与本地事务不同的是,分布式事务时要保证的是分布式环境下,不同数据库表中的数据的一致性现象。分布式事务的外理方案有多种,如XA协议、TCC三阶段提交、基于消息队列等等,本文只会涉及基于消息队列的外理方案!

  

   通过顶端的图亲们儿能看完,引入消息队列后,系统的繁杂性瞬间提升了,嘴笨 弥补了亲们儿第一种生活方案的哪几个过高 点,但也带来了更多的现象,比如消息队列系统一种生活的可用性、消息队列的延迟等等!但会 ,原先的设计依然这样外理亲们儿面临的核心现象-数据的一致性

  

   当然,分布式事务最好的外理方案是尽量外理跳出分布式事务!

   很多很多,亲们儿这里最核心的只是A银行通过本地事务保证日志记录+后台任务管理器池轮询保证消息不丢失。B银行通过本地事务保证日志记录从而保证消息不重复消费!B银行在回调A银行的接口也有通知外理结果,因为分析转账失败,A银行会根据外理结果进行回滚。

1、同步调用远程接口,因为分析接口比较耗时,会因为分析主任务管理器池阻塞时间较长。

2、流量只有很好控制,A银行系统的流量高峰因为分析压垮B银行系统(当然B银行肯定会有另一方的限流机制)。

3、因为分析“第1步”刚执行完,系统因为分析一种生活因为分析宕机了,那会因为分析A银行账户扣款了,但会 B银行这样收到接口的调用,这就跳出了有有一一个系统数据的不一致。

4、因为分析在执行“第3步”后,B银行因为分析一种生活因为分析宕机了而无法正确表态请求(实际上转账操作在B银行系统因为分析执行且入库),这事先A银行停留接口响应会异常,误以为转账失败而回滚“第1步”操作,这也会跳出了有有一一个系统数据的不一致。

   对于现象的1、2都很好外理,因为分析对消息队列熟悉的亲们应该更快能想到可不都时会 引入消息顶端件进行异步和削峰外理,于是又重新设计了有有一一个方案,流程如下:

   谈到本地事务,亲们儿因为分析都熟透悉,因为分析一些数据库引擎层面能支持的!很多很多也称数据库事务,数据库事务四大形态:原子性(A),一致性(C),隔离性(I)和持久性(D),而在这四大形态中,我认为一致性是最基本的形态,其它的有有一一个形态都为了保证一致性而处于的!

   然而,一切并这样这样顺利,刚过一会儿,app却如图二所示的提示我“因为分析收款人户名不符”因为分析转账失败!!!

1、A银行对账户进行检查校验,进行金额扣减。

2、将对B银行的请求异步写入队列,主任务管理器池返回。

3、启动后台任务管理器池池从队列获取待外理数据。

4、后台任务管理器池池对B银行接口进行远程调用。

5、B银行对转入账户进行检查校验,进行金额增加。

6、B银行外理完成回调A银行接口通知外理结果。

   面对上述现象,亲们儿不得不对系统再次进行升级改造。为了外理“A银行账户扣款了,但会 写入消息队列失败”的现象,亲们儿时要借助有有一一个转账日志表,因为分析叫转账流水表,该表简单的设计如下:

1、A银行对转出账户执行检查校验,进行金额扣减。

2、A银行同步调用B银行转账接口。

3、B银行对转入账户进行检查校验,进行金额增加。

4、B银行返回外理结果给A银行。

  在分布式系统中,分区容错性是基本要保证的。也只是说只有在一致性和可用性之间进行确定。一致性和可用性,为哪些地方不因为分析一块儿成立?回到事先修改列表的例子,因为分析数据会分布在不同的网络分区,必然会处于数据同步的现象,而同步会处于网络延迟、异常等现象,很多很多会跳出数据的不一致!因为分析要保证数据的一致性,这样就时要在对写库进行操作时,锁定一些读库的操作。只有写入成功且完成数据同步后,都时会 重新放开读写,而原先在锁定期间,系统丧失了可用性。更全部关于CAP理论可不都时会 参考这篇文章,该文章讲得比较通俗易懂!

   回到学生时代老师给亲们儿举的经典栗子,A账户给B账户转账400元(A、B处于同有有一一个库中),因为分析A的账户处于扣款,B的账户却这样到账,这就跳出了数据的不一致!为了保证数据的一致性,数据库的事务机制会让A账户扣款和B在账户到账的有有一一个操作要么一块儿成功,因为分析有有有一一个操作失败,则多个操作一块儿回滚,这只是事务的原子性,为了保证事务操作的原子性,就时要实现基于日志的REDO/UNDO机制!但会 ,仅有原子性还过高 ,因为分析亲们儿的系统是运行在任务管理器池池环境下,因为分析多个事务并行,即使保证了每有有一一个事务的原子性,仍然会跳出数据不一致的情況。类似A账户原先有400元的余额, A账户给B账户转账400元,先读取A账户的余额,但会 在一些值上减去400元,但会 在这有有一一个操作之间,A账户又给C账户转账400元,这样最后的结果应该是A减去了400元。但事实上,A账户给B账户最终完成转账后,A账户只减掉了400元,因为分析A账户向C账户转账减掉的400元被覆盖了!很多很多为了保证并发情況下的一致性,又引入的隔离性,即多个事务并发执行后的情況,和它们串行执行后的情況是等价的!隔离性又有多种隔离级别,为了实现隔离性(最终也有为了保证一致性)数据库又引入了悲观锁、乐观锁等等……本文的主题是分布式事务,很多很多本地事务就只是简单回顾一下,时要记住的一些是,事务是为了保证数据的一致性

   前三三五天发了工资,第一反应是想着要给远方的女亲们一些惊喜!于是打开了平安银行的APP给女亲们转点钱!填写上对方招商银行卡的卡号、开户名,一键转账!读懂!在我点击的那瞬间,就收到了app的账户变动的提醒,但会 跳出了图一所示的提示界面:“外理中,正在停留对方银行返回结果…”。嗯!毕竟是跨行转账嘛,等个几秒也正常!脑海后后后后刚开始英文浮现出女亲们收到转账后惊喜与感动的画面!

   一些流水表时要为何在么在用呢?亲们儿在“第1步”进行扣款时,一块儿往流水表写入一条操作流水,情況为“待外理”,但会 这有有一一个操作时只是原子的,也只是说时要通过本地事务保证这有有一一个操作要么一块儿成功,要么一块儿失败!这就保证了倘若转账扣款成功,必定会记录一条情況为“待外理”的转账流水。因为分析在一些步失败了,那自然只是转账失败,这样后续操作了。因为分析这步操作后系统宕机了因为分析这样将消息成功写入消息队列(也只是“第2步”)也没关系,因为分析亲们儿的流水数据因为分析持久化了!这事先亲们儿只时要加入有有一一个后台任务管理器池进行补偿,定期的从转账流水表中读取情況为“待外理”且最后更新的时间距当前时间大于某个阈值的数据,重新装到去消息队列进行补偿。原先,就保证了消息即使丢失,也会有补偿机制!B银行在外理完转账请求也有回调A银行的接口通知转账的情況,从而更新A银行流水表中的情況字段!原先就完美外理了上有有一一个方案中的有有一一个过高 点。系统设计图如下:

  

  CAP理论是由加州大学Eric Brewer教授提出来的,一些理论我不知道们,有有一一个分布式系统不因为分析一块儿满足一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)这有有一一个基本需求,最多只有一块儿满足其中两项。

  一致性:这里的一致性是指数据的强一致,也称为线性一致性。是处于分布式环境中,数据在多个副本之间否是是都都时会 保持一致的形态。也只是说对某个数据进行写操作后立马执行读操作,时都时会 读取到事先写入的值。(any read operation that begins after a write operation completes must return that value, or the result of a later write operation)

  可用性:任意被无故障节点接收到的请求,时要都都时会 在有限的时间内响应结果。(every request received by a non-failing node in the system must result in a response)

  分区容错性:因为分析集群中的机器被分成了两帕累托图,这两帕累托图只有互相通信,系统否是是能继续正常工作。(the network will be allowed to lose arbitrarily many messages sent from one node to another)

   到目前为止,亲们儿很好的外理了消息丢失的现象,保证了倘若A银行转账操作成功,转账的请求就一定能发送到B银行!但会 该方案又引入了有有一一个现象,通事先台任务管理器池轮询将消息装到去消息队列外理,同一次转账请求因为分析会跳出多次装到去消息队列而多次消费的情況,原先B银行会对同一转账多次外理因为分析数据跳出不一致!那为何在么在保证B银行转账接口的幂等性呢?