当前位置: 首页 > 科技观察

一次跨行取款失败,而引发对分布式事务的思考

时间:2023-03-13 14:51:05 科技观察

一次跨行取款失败,引发了对分布式交易的思考会帮你先扣1000块钱,然后ATM吐钱。但是如果提款机出现问题,你会发现钱被扣了,但是钱并没有被取走。第一次遇到这个问题的时候非常担心。当时我跨行取了3000元,短信提示已经扣钱了,但是钱没有取出来。收到交易提示,钱已退!在这个事件中,引发了一个关于数据一致性的思考。根据整个资金处理环节的经验,大致流程如下:场景分析如果真实场景是我画的这张图,会出现几个问题。A银行调用B银行远程接口同步扣款。如果接口处理比较耗时或者出现网络故障,都会造成比较长的阻塞时间。那么给用户的感觉就是取款机页面一直在兜圈子。支付失败时,A银行本地交易表状态变为4支付失败,同步调用B银行接口回滚扣款3000元。如果回滚失败,会扣掉用户的钱,但不会提现。远程接口的异步调用在调用第三方的过程中不能使用同步方法,有一定的性能要求。所以如果我们把第一个流程的异步流程通过异步化改造一下,我之前在做支付业务的时候,就是这么干的。A银行调用了B银行的接口,引入了异步消息队列,将所有交易指令直接丢给消息队列进行异步处理。B银行收到指令并执行后,通过http协议将结果写回给A银行。回滚A银行支付失败的数据。方案出台后会带来什么问题我们先不管,先把原来的问题解决掉。当ATM取款失败时,交易将被回滚。根据上图,其实是有一个数据一致性的问题,就是交易记录表一定要记录交易失败,钱要退回账户。这种一致性问题其实就是大家所说的分布式事务问题。分布式事务问题也称为分布式数据一致性问题。其实在分布式架构中,分布式事务问题是一个非常普遍的问题。既然常见,就一定有解决办法。这里我不去展开他的各种解决方案,而是跟大家讲讲架构的思维层次。首先,我们知道数据库事务会满足ACID特性:原子性(A);一致性(C);隔离(一);坚持(D);这四个特征中,一致性是最基本的特征,其他三个特征的存在就是为了保证一致性!在分布式场景下,这种单库事务是没有意义的。分布式场景下的事务一致性方案在分布式架构中,一致性问题的解决方案有很多,比如TCC(TransactionCompensation),比如基于可靠性消息的最终一致性,比如基于2pc协议的强一致性,对于共识协议中的中间件很多,有paxos、Raft等算法;你可以自己检查这些。前面我们说过,在分布式架构下,分布式事务的问题是非常普遍的。因此,市场上有许多可用的解决方案。那么这里涉及到两个概念。一种是强一致性,一种是弱一致性。所谓强一致性,就是保证跨节点数据的强一致性,要么同时成功,要么同时失败。它是一种最终一致性。CAP和BASE的强一致性和弱一致性有什么区别,或者对系统会有什么影响?我们来分析一下CAP定理,也称为布鲁尔定理。对于设计分布式系统(不仅仅是分布式事务)的架构师,CAP是您的入门理论。1.C(Consistency):对于一个指定的client,读操作可以返回最新的写操作。对于数据分布在不同节点上的数据,如果在某个节点上更新了数据,如果在其他节点上可以读取到最新的数据,那么就称为强一致性。如果获取到,则为分布不一致。2.A(可用性):非故障节点在合理的时间内返回合理的响应(不是错误和超时响应)。可用性的两个关键是合理的时间和合理的响应。合理的时间是指不能无限期地阻止请求,应该在合理的时间内返回。合理的响应意味着系统应该清楚地返回结果并且结果是正确的3.P(分区容错):当网络分区发生时,系统可以继续工作。比如集群有多台机器,其中一台机器网络出现问题,但是集群还能正常工作。熟悉CAP的人都知道,三者不能共用,因为在分布式系统中,网络不可能100%可靠,分区其实是不可避免的现象。如果我们选择了CA,放弃了P,那么当出现分区的时候,为了保证一致性,此时必须拒绝请求,但是A不允许,所以分布式系统选择CA理论上是不可能的架构,只有CP或AP架构。对于CP,放弃可用性,追求一致性和分区容错。对于AP来说,放弃一致性(这里说的一致性是强一致性),追求分区容错性和可用性是很多分布式系统设计的选择,后续的BASE也是基于AP进行扩展。BASE是BasicallyAvailable(基本可用)、Softstate(软状态)和Eventuallyconsistent(最终一致性)三个词组的缩写,是CAP中AP的延伸。基本可用:当一个分布式系统出现故障时,允许丢失部分可用功能,以保证核心功能可用。Softstate:允许系统存在一个不影响系统可用性的中间状态,这里指的是CAP中的不一致。最终一致性(FinalConsistency):最终一致性是指经过一段时间后,所有节点的数据都会一致。BASE解决了CAP中没有网络延迟的理论,在BASE中使用软状态和最终一致性来保证延迟后的一致性。对于互联网公司来说,用户体验是最重要的,所以为了避免强一致性带来的阻塞,会采用最终一致性方案来解决数据一致性问题。用的最多的是基于本地消息表+异步队列,基于消息队列的可靠性来实现最终一致性的方案。支付失败场景转换是基于该理论的。我们可以思考和改造退出的逻辑。这个链接在这里。结束了吗?事实上,仅仅使用可靠性消息队列来保证数据的最终一致性是不够的。如果消息队列本身的可靠性有问题,也会造成数据不一致。因此,一般的做法是在银行A端创建一个本地消息表,记录这条消息的处理情况。然后通过定时任务轮询消息表,实现数据最终一致性。消息表设计消息表有交易必须使用的业务字段,也有设计用来重发消息的辅助字段。Id交易流水号status交易状态lastUpdateTime最后更新时间