热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

异构交易场景交互流程及一致性保证

问题如下:A系统联机同步调用B系统(A和B不是同一公司系统,不能用分布式事务),如何保证系统间数据准实时一致

问题如下:

A 系统联机同步调用 B 系统(A 和 B 不是同一公司系统,不能用分布式事务),如何保证系统间数据准实时一致性(聊聊设计思路即可)?

提醒:需要考虑调用超时、并发、幂等、反交易先到等。

各种异常场景怎么处理要考虑更完善些,如事务隔离、并发、反交易先到调用方和服务方约定(前端客户不可能一直等着)

这种聊思路的问题,往往问的都很大,或者说比较唬人,实际上遇到这种问题,我们要做的就是抽象。抽象出场景,抽象出问题的核心要点。我们能够提炼出要点:

  1. 非同一公司系统(跨网络,异构);
  2. 反交易先到(我们基本能确定提问者大概想知道的思路与交易有关);
  3. 服务方预定;
  4. 前端客户不可能一直等待(交易流程往往是长事务流程,不能简单依靠单个接口调用,基本上是异步流程)。

有了这些前提,我们就可以基本抽象出讨论的背景和模型。


一、模型与背景提炼

因为前提是 A、B 系统分属不同的公司,也就是说 A B 系统是通过公网进行交互的两套异构系统,极有可能实现的技术栈也各不相同,因此互相之间只能通过暴露在外的接口进行交互,我们就认为是通过 http 接口进行的交互。

由于是 A 系统调用 B 系统,因此我们可以抽象为点对点的消息通信场景,其中 A 为主动拉取方,B 为被拉取方。

问题提到说,我们说不能用分布式事务,其实是在说不能使用强一致 / 类 2PC 的事务实现,如 2PC、3PC、SEATA 等,但是可以利用诸如最大努力通知的柔性方式进行数据的同步

有了方案,我们接着抽象出 交易单 这个模型,并为其指定状态机:

  1. 交易单创建时,状态为 初始化,
  2. A 系统向 B 系统发送交易单时改为, 处理中
  3. 如果 B 系统同步响应收单失败,则 A 系统修改状态为 失败
  4. 同步 B 系统同步响应收单成功,则 A 系统修改状态为 已提单
  5. 当 B 系统处理交易完成,通知 A 系统交易完成,则 A 系统修改交易单状态为 成功,(此处的成功为真实成功,因为已经发生了资金扣除 / 积分等标的物的消耗)
  6. 当 B 系统处理交易失败,则通知 A 系统交易失败,则 A 系统修改交易单状态为 失败 (此时的失败假定为 B 系统在扣钱之前就失败)

二、超时处理方式

我们讨论一下提单请求发生超时应当如何处理。

A 系统的出口网关向 B 系统的入口网关发起提单请求,这是一个同步通信,对于同步请求的失败(如:签名失败,参数异常失败等),A 系统可以发起重试,此时这种请求属于真实的失败,因为压根没有发起交易行为,所以原则上数据是一致的,对于资金而言就是没有发生扣减等行为。


三、掉单查询 

如果 A 系统提交提单请求超时,此时未能收到 B 系统回复的同步 收单成功 的响应,则这时候就存在数据不一致的情况。这个场景就是所谓的 掉单,则 A 系统需要对掉单的数据(状态为处理中)发起掉单查询操作,思路就是定时发起查询,获取 B 系统对交易单的处理情况。

一般而言 B 系统都会通知 A 系统发起掉单查询的建议时间,如发起交易单 10 分钟后即可有处理的确定结果,那么 A 系统就可以对已提交 10 分钟以上,状态为 处理中 的交易单发起掉单查询。也就是说,10 分钟后,这类中间态的数据,AB 系统间可以达成一致。

特别的,如果一次掉单查询没能查到确定的结果,则可以设置下一次继续查询,这里推荐采用     时间衰减策略 进行查询,这是交易场景乃至中间件中常用的一种未知数据定时同步的通用思路。


四、结果通知 

对于交易场景,处于对数据实时性的考虑,我们常常希望下游系统处理完数据之后能够及时通知我们结果。

在这个场景中就是 A 系统需要对接 B 系统的 交易结果实时通知接口,当交易单被 B 系统处理完成之后,B 系统会对交易单处理结果发起通知,及时回调 A 系统处理的结果。此时,A 系统成为被调用方,B 系统为调用方,相比于掉单查询,结果通知几乎是准实时的,从 B 系统发起通知到 A 系统接收到通知往往都在百毫秒级别(支付宝支付结果通知能够达到数十毫秒)。

简单总结下,对于超时的处理,我们就是通过掉单查询实时通知方式,通过主动轮询处理结果与被动接受结果通知的方式,通过推拉结合的方式共同保证 AB 系统之间的数据达成最终一致。


五、并发提单 

对于并发提单而言,其实属于老生常谈类的话题。其本质在于分布式场景下请求的防重放处理思路

核心就在于请求串行化,我们往往通过 CAS、加锁等方式进行处理。

具体到具体的实现细节,CAS 方式有数据库状态标识(状态机)、加锁方式其实就是分布式锁,简单的说就是通过分布式锁方式进行处理,通过对一笔交易单加分布式锁,获取分布式锁成功的请求才能发起请求,发起请求后写入幂等记录,完成请求后释放锁,防止并发提交。


六、幂等思路

对于幂等而言,我们通常需要通过幂等校验来进行,比如:

高并发场景下,将幂等标识写入 Redis 缓存,用于对写请求幂等 或者 请求如果量不大,则通过数据库唯一约束进行幂等处理,保证只有一笔交易单落库(如唯一约束 订单号)。

唯一约束是最后一道防线,用于对写请求幂等 低并发场景下,通过先查询,后插入(更新)的方式也可以进行幂等校验,但是高并发场景下会有重复更新 / 新增的风险,因此往往需要配合分布式锁共同作用,将并发请求串行化 单单就幂等来说,查询天然幂等,更新则可以通过上面的方式进行幂等保证。


七、反交易先到

首先明确何为 “反交易”,反交易,顾名思义,反向交易,我们举个例子就好懂了。

比如说,扣款的反交易,就是冲正(比如说,转账操作,扣除 A 的钱,给 B 加钱失败。则 A 扣除的钱需要补回,这个过程就是冲正。实际的冲正涵盖的范围更广,我们只需要简单认为是扣款的反向操作,但是要区别于提现和充值。)

比如说,A 系统请求对交易单支付 100 元,B 系统扣款成功后向 A 系统返回支付成功的通知消息;此时 B 系统后续操作故障,导致该交易无法继续进行下去,则 B 系统对 A 系统扣除的 100 元执行了冲正之后,通知 A 系统交易已冲正退单。

所谓反交易先到,就是说网络发生拥塞,导致冲正退单的消息,先于支付成功的消息先到了。

我们的 A 系统的交易单不是有状态机么,状态机就是处理反交易先到的利器。

我们要求对于交易的处理是串行的,如何串行,其实简单的说,通过状态机就能很好地实现。

当然要说明的一点是,对于实际情况,需要具体业务具体分析,对于我们当前讨论的场景而言,我们通过状态机能够解决问题,具体过程如下,

我们假定,A 系统的交易单的状态机只能按照 处理中 -> 支付成功 -> 退单 这个流程进行流转,当退单先于支付成功到达时,我们需要在一个事务中同时完成流水的插入,交易单状态的更新。对于更新操作而言,我们的 sql 期望如下:

update order set order_status=退单 where order_status=支付成功 and order_id=xxxxx

由于状态机只允许固定的订单状态迁移,我们在更新状态的时候带上老状态,实际上当前的 order_status = 处理中,因此 update 失败。最终处理为通知处理失败,A 系统告知 B 系统对该通知进行重发。那么 B 系统就只能老老实实的重新发起通知,这也是一个合格的交易系统所必须具备的能力。否则你的系统不支持通知重复发起,用户体验也太差了。

此时由于状态机的原因,交易单状态还是处理中,当被拥塞的支付成功的通知到达,交易单状态成功更新为 支付成功 此时执行的 update 语句为:

update order set order_status=支付成功 where order_status=处理中 and order_id=xxxxx

后续重试的 退单通知(所谓的反交易)到达后,交易单根据状态机便能够成功进行流转,具体的 update 语句如下:

update order set order_status=退单 where order_status=支付成功 and order_id=xxxxx

从我们的分析看出,只要有状态机存在,无论如何,交易单的状态只能按照 处理中 -> 支付成功 -> 退单 这个方式流转而不会发生状态的跃迁跳跃。

所以我们说,状态机,就是系统间处理反交易先到的利器,状态机也是交易类系统通用的神兵利器。


八、前端用户不能一直等待处理思路

还有一点就是前端客户不可能一直等着,实际上在上述的过程中我们已经解答了这个问题。

我们本次分析问题采用整体的方案是基于最大努力通知的思路,核心的步骤就是 同步提单,掉单查询,结果通知。通过对这几个步骤进行结合,我们就能够避免前端一直等待,因为交易属于一个长事务业务,上游 / 前端只需要提交成功就可以去干别的事情了,剩下的复杂操作让下游系统慢慢处理,这其实就是体现了异步的思维


九、通过对账保障数据一致性

最后还要提一下,对于交易系统而言,数据一致性保证的兜底方案就是对账机制,关于对账,我在近期也会单独写一篇文章进行详细讨论(又一个 flag)。

交易系统通常具备 t+1 的对账,简单的说就是,每天生成前一天的对账单,在我们的这个场景中,A 系统每天都向 B 系统请求自己前一天的交易对账单,下载到本地,通过 A 系统自己的渠道流水号 / 交易单号,与 B 系统提供的交易单进行逐条的对账,这个过程往往能够通过定时任务来自动化的执行,把不一致的交易单对平。从而将两个系统之间的数据达成最终一致,比如说,A 系统没收到 B 系统的通知,掉单查询也没有查到的交易单,往往最终通过对账都能够获取到数据的最终状态。



推荐阅读
  • 14亿人的大项目,腾讯云数据库拿下!
    全国人 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
  • 一面自我介绍对象相等的判断,equals方法实现。可以简单描述挫折,并说明自己如何克服,最终有哪些收获。职业规划表明自己决心,首先自己不准备继续求学了,必须招工作了。希望去哪 ... [详细]
  • 缓存 分布式锁 Redis
    分布式锁现在Redis基本上没家公司都在使用,只是各自使用的场景不以,但Redis最出名的还是做为缓存服务器,提搞服务器的的吞吐量,下面我们来围绕这个作为缓存做一个总结今天的目标其 ... [详细]
  • t-io 2.0.0发布-法网天眼第一版的回顾和更新说明
    本文回顾了t-io 1.x版本的工程结构和性能数据,并介绍了t-io在码云上的成绩和用户反馈。同时,还提到了@openSeLi同学发布的t-io 30W长连接并发压力测试报告。最后,详细介绍了t-io 2.0.0版本的更新内容,包括更简洁的使用方式和内置的httpsession功能。 ... [详细]
  • 本文介绍了Redis中RDB文件和AOF文件的保存和还原机制。RDB文件用于保存和还原Redis服务器所有数据库中的键值对数据,SAVE命令和BGSAVE命令分别用于阻塞服务器和由子进程执行保存操作。同时执行SAVE命令和BGSAVE命令,以及同时执行两个BGSAVE命令都会产生竞争条件。服务器会保存所有用save选项设置的保存条件,当满足任意一个保存条件时,服务器会自动执行BGSAVE命令。此外,还介绍了RDB文件和AOF文件在操作方面的冲突以及同时执行大量磁盘写入操作的不良影响。 ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了软件测试知识点之数据库压力测试方法小结相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 2021最新总结网易/腾讯/CVTE/字节面经分享(附答案解析)
    本文分享作者在2021年面试网易、腾讯、CVTE和字节等大型互联网企业的经历和问题,包括稳定性设计、数据库优化、分布式锁的设计等内容。同时提供了大厂最新面试真题笔记,并附带答案解析。 ... [详细]
  • 云原生应用最佳开发实践之十二原则(12factor)
    目录简介一、基准代码二、依赖三、配置四、后端配置五、构建、发布、运行六、进程七、端口绑定八、并发九、易处理十、开发与线上环境等价十一、日志十二、进程管理当 ... [详细]
  • 旁路|发生_Day749.旁路缓存:Redis是如何工作的Redis 核心技术与实战
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Day749.旁路缓存:Redis是如何工作的-Redis核心技术与实战相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 关于我们EMQ是一家全球领先的开源物联网基础设施软件供应商,服务新产业周期的IoT&5G、边缘计算与云计算市场,交付全球领先的开源物联网消息服务器和流处理数据 ... [详细]
  • 本文介绍了在Oracle数据库中创建序列时如何选择cache或nocache参数。cache参数可以提高序列的存取速度,但可能会导致序列丢失;nocache参数可以避免序列丢失,但在高并发访问时可能导致性能问题。文章详细解释了两者的区别和使用场景。 ... [详细]
  • 上图是InnoDB存储引擎的结构。1、缓冲池InnoDB存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。因此可以看作是基于磁盘的数据库系统。在数据库系统中,由于CPU速度 ... [详细]
  • 深入理解Java虚拟机的并发编程与性能优化
    本文主要介绍了Java内存模型与线程的相关概念,探讨了并发编程在服务端应用中的重要性。同时,介绍了Java语言和虚拟机提供的工具,帮助开发人员处理并发方面的问题,提高程序的并发能力和性能优化。文章指出,充分利用计算机处理器的能力和协调线程之间的并发操作是提高服务端程序性能的关键。 ... [详细]
  • 1Lock与ReadWriteLock1.1LockpublicinterfaceLock{voidlock();voidlockInterruptibl ... [详细]
author-avatar
静-静-静距离
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有