无敌码农

其他

支付系统订单模型该如何设计?

导读最近经历了一件事,就是小码农所在的公司因为被某大厂收购之后要进行融合了,其他方面的融合就没必要说了,今天咱们只是聊一下支付系统融合的事情。首先从很多互联网公司的发展经验来看,随着多条业务线的发展,最终都是会催生出建设统一支付系统的强烈需求。这是为什么呢?因为支付系统太重要了,它拥有公司所有的现金流水,是进行业务清算、财务核算、上市审计以及后续各类财务信息管理的关键系统之一。一家公司被收购后新老板们最关心的事也莫过于财务数据的准确性了,之前小码农从事支付系统的研发工作加入的都是已经比较成熟的团队,去建设的支付系统也都是为了帮助所在公司来实现上述的目标和战略,而所采用的策略也都是在强大的上层的支持下进行业务线统一支付入口的归集。只不过这一次作者所加入的是一家互联网创业公司,而在支付系统的建设上,也属于比较混乱和初级的阶段,因此在被收购后属于是在另外一个强大上层的支持下而被统一的一方而已。当然从客观的角度看,这也是一件非常合理的事情,因为一个大的集团公司无论是从成本还是统一管理的角度看都是没有必要重复建设多套支付系统的,而对一家被收购的公司而言,其支付系统肯定也是首先需要被融合的关键系统之一。作者对此持开放和乐观的态度,即使这个过程对个人会有一些影响。只是因为在此之前经历了很多的坎坷,觉得有很多事情还是值得总结一下,因此才想着写一篇文章来回忆下这个过程。而总结的目的,也只是希望能够对未来会经历这样一个过程的公司,有一点参考价值,因为即便是被融合,如果做的比较好的话也会让融合的过程会更加容易一些,至少还能得到一些口碑,否则就很容易遭人骂了,而从技术本身看也会是一种失败。被忽视的团队关于支付团队是否是被忽视的团队的问题,可能因公司而异(或者也许因不同公司处于关键岗位的技术Leader是否具备这样的经验和远见而异),可能有一些互联网创业公司在发展初期并不是很Care这件事,因为早期的业务也确实没有那么复杂,在业务代码中接个微信、支付宝能有多难,两三个人都嫌多还想引起什么样的重视?的确,作者最开始加入这家互联网创业公司时,真的就只是在业务代码中对接了一个支付宝、微信,看起来好像真的是没有那么复杂,在人员方面也就是两个没有太多支付经验的研发而已,连正式的支付订单流水表都没有,还基本上是与业务订单耦合在一起的那种。然而,似乎这一切好像也并没有影响公司业务的蓬勃发展,在线收款业务量也是增长迅速,每天好几个亿的进账。只是这个时候,会偶尔出现很多掉单而已,反正用户投诉了,写条SQL改下订单状态,要么退款,要么用SQL进行下业务处理。总之,看起来一切并没有那么复杂,只是后面又增加了几个新的支付渠道,而支付宝、微信这种因为开了新的入口(如和微信小程序合作,支付宝第三方合作之类)又申请了下新的微信、支付宝商户号。从截止到以上阶段的场景上分析,到目前为止都只是在单向的进行收款操作。而随后的事情可能就有点戏剧性了,因为突然某一天,发生了挤兑的事,系统的退款请求迅速增加,当然,此时大部分的退款请求还都只是走原路进行全额退款的操作,还没有部分退款等一些复杂的业务退款情况,而此时的退款掉单则有点扯了,因为这导致了大量用户已经退款,而业务系统逻辑并没有更新状态的情况,此时此刻也就为后续财务数据的混乱埋下了相应地伏笔(之前的支付掉单处理得不及时,也是在埋伏笔)。似乎更为糟糕的是,因为有些用户太过于忠诚,支付的订单时间过长,已经超出了第三方渠道允许进行原路退款返回的期限,而此时因为无法通过系统自动进行原路退款,最终没有办法客服小姐姐只能人工收集客户上报的资料(如支付宝账号),然后通过Excel由哪两位苦逼的开发去通过手工的方式整理后通过单独申请的支付宝代付账号进行转账退款操作,似乎这种方式也没有什么太大问题,只是比较原始而已。的确是这样,然而不幸的是,只是这种人工操作偶尔还会失败,需要重新发起和进行系统订单状态的更新(如果真的把钱给别人转成功了,得用SQL把状态给改了啊),而这个过程因为人工因素,导致了一些状态未更新的情况,以及转账重复的小失误,而这也为后续财务数据的混乱埋下了另外一笔伏笔。看到这里,也许不少同学都会诧异,这尼玛为啥不设计相应的机制来解决呢?所以,这个时候开始有人谈起了支付系统重构的问题。而此时作者正好加入这家公司,所以心想也算一个机会,于是也提出的自己的重构方案。细节不提了,只说一个基本的支付系统应该是什么样,如下图所示:于是作者激情满满的找到了领导,提出了自己的想法。然而,令人没想到的是,还有个Secret项目因为也涉及到一些支付功能的重构,所以需要找人相关人员沟通下,好吧,此时才知道原来支付系统已经在秘密地被重构了,只是正常开发和维护支付系统的人居然不知道这件事。也罢,而让人更意想不到的事,这是居然还不算完,因为还有另外一个团队,属于另外一个VP领导下的团队也在进行支付系统的重构,只是正常的支付团队以及秘密重构的项目都还彼此不知道而已。说到这里,仔细想想,作者也是很诧异,不过好歹因为作者提出的这个想法并鼓足勇气和大佬沟通,总算让大家彼此知道了这件事,也算是一个良好的进步和开端。而与此同时,还有另外一个团队在开发所谓的财务系统(实际上就是作者图中所规划的账务系统,当然后者因为种种扯淡的因素,在做了两月之后做黄了,以至于到目前为止仍然缺失这一块,而收购方希望融合方式则正是所有的业务线接入他们统一收银台的同时,还需要接入其账务系统,这样资金流、业务流就完成双向闭环了,这样业财核对、收入计算就可以通过集团统一而完备的系统进行集中处理了)。于是乎,好像此时此刻,这件事应该是向着好的方向发展了,支付系统应该是在比较充足的资源配置的情况下,并且经过合理的设计后开始有计划有步骤地重构了。然而,不幸的事,此时此刻又出现了新的搅局者,新来了一位似乎很有经验的产品经理,提出要建设一套很牛逼的统一交易系统,而支付系统当然只是其中底层的一个小部分而已。如此这般,最终经过N轮的扯皮、沟通以及团队利益的纠结争斗,最后就由某某团队开始进行支付系统的重构了,与此同时作者呢因为刚来,所以就做起了大家都觉得很不起眼的对账工作了。然而,后续支付系统的重构,并没有完成彻底的重新塑造,整个系统的订单模型并没有进行脱胎换骨的改造和升级,对于历史数据的处理,也是避重就轻,只是简单的在新的支付系统的代码层面进行了适配,并采用了无敌的双写策略,如此至今还是双写(客观地究其原因,因为那个团队实际参与重构的也只有2~3人,在经验和资源缺乏的情况下,也很难将这件事做的相对全面而完整)。以上种种也就为支付系统的先天残缺,资金数据的混乱以及后续为了适配各种新业务而疲于奔命,从而导致更多的不确定埋下了深深的伏笔。而这其中,又经历了不同主管Leader的更换,但似乎没有一个是专业的,于是造就了现如今的种种乱象。通过上述的坎坷历程的回顾,这可能并不像是一个技术问题,而更多的像是因为创业公司的技术管理混乱而导致一种扭曲的现象。也许换一个CTO就不一定会是这种状态,所以这种情况是否属于共性问题,也就需要大家自己根据自身公司的实际情况进行判断了。只是在这里作者将其笼统的归咎为对支付团队统一建设的一种忽视吧。有问题的组织关于这个问题,不同的公司的情况可能是不一样的,正如上面所说,早期在业务代码中对接个支付宝、微信的接口也许并不是太复杂的事,但是需要说明的是如果考虑到未来业务的扩展所导致的复杂性,并且在已经开始重构支付系统的情况下,则是一定要做到“麻雀虽小,五脏俱全”,之所以这么说,原因在于支付系统是一种对数据一致性要求非常高,但是又很难单纯的从某一个小的方面保证数据一致性的系统,它需要一个完整的体系来保证。而上面提到的复杂性,就有很多种情况了,例如如果涉及系统退款,退款本身就会存在诸多的复杂性,如全额原路退款、部分原路退款、在线转账退款、线下转账退款等,并且不同的支付渠道所能支持的程度还有差异。另外,如果涉及多渠道、同一渠道不同的商户主体,以及银行卡支付/非银行卡支付,海外支付多发的ChargeBack等情况,则带来的复杂性也会相应地增加。因为此时支付系统不仅需要满足参数配置化、渠道路由化等要求,支付方式、交易方式所产生的数据订单也需要具备完整的存储逻辑。当然,上述逻辑复杂度的增加也不是一开始就是这样的,而是随着业务发展逐步递增的。所以对于支付团队的配置,也没有必要一开始就配置一个大的团队,但是作为团队的技术Leader,一定要清楚在什么阶段需要什么样的人员配备,并且明确的指定一名具有一定专业度的支付团队技术Leader来带头进行有组织、有计划地重构工作,而不是在这个问题上含糊不清,因为按照个人的经验,在这个事情上的瞎竞争其实是没有什么好处的,最终可能会带来混乱。支付订单模型在具体讨论如何对支付订单模型进行设计讨论之前,和大家一起回顾了一些团队发展和建设的问题,因为至少在作者目前看来,最本质的问题并不是出在技术本身上,而是因为团队技术管理混乱,带来了一系列的恶果。但很多时候,也许以上种种并不是我们作为普通技术人员本身能够干预得了的,因为这往往牵扯很多技术以外的因素。那么如果假设你承担了这一角色,或者作为一名具体的工程师,在你具体重构或设计支付系统时,如何尽可能地想得长远一些呢?这里有作者根据自身经验设计的一套逻辑模型,供你参考。上图是一张精简的关于支付系统订单模型设计的图,在模型中我们将订单分为交易&支付两个层面,之所以要这么划分,是在于我们进行支付系统开发时很多时候是需要满足一部分业务逻辑的,而设置交易订单的目的则是为了屏蔽这种业务不确定性而带给支付订单本身的复杂性。在这个模型中,交易订单作为与业务交易映射的一张记录表,例如业务A通过支付系统发起了一笔充值交易(如10块钱),那么就会在交易订单中插入一条10块钱的充值交易流水,而这笔充值流水正常情况下可以通过相应地支付渠道进行支付,可以一次性支付10块钱(插入一条对应的支付订单流水),也可以支付两次5块钱,并且还可以分别使用不同的支付渠道(分别插入两笔对应的5块钱的支付订单流水),所以交易订单与支付订单的关系为1:N。之所以允许这样的情况发生,是因为在实践中,因为渠道限额,业务允许重复发起支付等原因,所以必须允许进行拆单支付的情况发生。而如果在这种情况下又需要允许交易进行退款的话,为了精简数据存储,对于交易订单可以通过状态机进行处理(如设置交易退款状态),而对于支付来说,退款本身也是支付流水,所以不应该直接在支付订单流水上进行状态更改,而是应该单独设计独立的退款流水表,只是需要在退款流水表中设置原始支付的订单信息,以及退款的具体方式即可。而支付退款本身又可以分为原路退款/非原路退款,而这两种退款方式又分别可以分为全额退款和部分退款两种情况,所以支付流水与退款流水之间又存在1:N的关系。还是举上面那个例子,如果用户充值交易所支付的10块钱,是一次性通过微信支付的,那么退款时如果时全额原路退款,则只需要插入一条与支付流水对应的10块钱的退款流水,并更新交易订单状态为“已退款”即可。如果是因为该用户的充值部分,使用了5块,剩下的5块钱可以退款,那么此时发起的就是原路部分退款,在退款流水表中插入一条与支付流水相关的5块钱的退款流水即可,但是此时需要将对应的交易订单状态更新为”部分退款“的状态。此外,以上情况如果由于支付订单时间太久,原支付渠道已无法再进行原路退款,此时只能通过线上或线下转账方式/代付方式进行退款的话,则为了完善模型,我们也需要在退款流水表中记录一条与原支付订单关联的退款流水,只是退款方式需要记录非原路退款的情况,并且在发起转账或代付退款后,需要在退款流水中关联对应的转账或代付流水号,之后根据实际退款的情况更新对应的交易订单状态为“已退款/部分退款”。而转账或代付本身因为又是一种单独的支付方式,所以此时我们需要在支付流水表中单独记录转账订单或代付订单,但因为此时与交易订单本身无直接关联,所以不需要产生新的交易流水。对于海外支付渠道因为产生了ChargeBack的情况,我们需要将其视为与转账类似的非原路退款方式,从而进行退款流水的记录,以及ChargeBack订单本身的记录,这一点对于海外支付渠道的支付逻辑完善以及ChargeBack本身的追溯会比较重要。按照这种模型进行支付订单结构的设计,并在一开始就撸清楚这些支付场景的对应的数据存储逻辑,会对未来系统的拆分扩展大有好处,因为至少数据逻辑是非常清晰的了。只是为了确保这套数据逻辑的一致性,我们还需要加强对账系统关于内部订单对账的逻辑,确保不出现异常和不一致的数据问题。以上就是本次作者关于支付部分想写的全部内容了,希望能够对一些正在经历支付系统构建的朋友们无论好坏有一点参考借鉴的意义。谈一下家国情怀在这里上面干货部分的内容就说完了,接下来的内容纯属表达下心情,希望见谅!最近因为华为事件,作者也看了很多报道和相关的分析文章,总结一点就是华为的5G太强大,触动了以美国为主导的西方利益,因为一旦5G网络建设的主导权被中国公司掌握,那么未来世界的网络格局就要发生翻天覆地的变化了,所以美国开始搞一些下三滥的绑票手段了。在这里作者作为一名中国人,对此表示强烈的愤慨,同时也认识到这个世界还是一个弱肉强食的世界,之前很多人都说美国这里好,哪里好的,当然我也承认美国的确在很多方面还领先中国,但是正所谓“金窝银窝不如自己的狗窝”,还是希望大家多多爱自己的祖国,不要时不时的随波逐流喷我们国家这不好,那不好的了。做好自己的本质工作,不求为国做多大贡献,但求不给国家添乱就行!最后,以本文的封面表达下对华为这家伟大企业的支持!谢谢大家!推荐阅读:支付对账系统怎么设计?互联网账户系统如何设计(上篇)?互联网账户系统如何设计(下篇)?支付渠道参数如何设计成路由化配置?移动端支付系统如何设计有效地防重失效机制?—————END—————识别图片二维码,关注“无敌码农”获取精彩内容
2018年12月17日
其他

图解:什么是Raft算法?

导读在之前的文章《基于SpringCloud的微服务架构演变史?》中我们介绍了分布式注册中心Consul集群中使用了Raft这种分布式一致性算法,那么在这一篇的内容中就给大家详细介绍下什么是Raft算法。我们知道进行微服务架构很重要的一个目标就是实现分布式提升整体系统的性能和可靠性。而提供系统可靠性的关键就是通过建立多个副本节点的方式来保证系统中一台或多台服务节点故障的情况下,系统仍然可用。但是多个副本之间的数据一致性如何保证,就成了一个新的问题,而分布式一致性算法就是为了解决分布式环境下多副本之间数据一致性问题的。在基于SpringCloud的微服务体系中,Consul作为整个服务的注册中心,处于十分关键的位置,所以Consul在生产环境下都是以集群的方式来提供服务的,而整个Consul集群间的节点数据同步就需要像Raft这样的一致性算法来实现。下面我们就以图解的方式来深入了解下Raft的工作机制!Raft的角色在Raft算法中节点存在Follower、Candidate、Leader三种状态。Raft节点选举(Leader
2018年11月21日
其他

基于SpringCloud的微服务架构演变史?

Cloud则是基于Springboot提供的一整套微服务解决方案,因为技术栈比较新,并且各类组件的支撑也非常全面,所以Spring
2018年11月15日
其他

支付对账系统怎么设计?

所以,在进行某个渠道对账时需要根据条件将账单数据、支付平台订单数据分别清洗到两张中间表中,分别叫做账单待对账中间表(A表)、订单待对账中间表(B表),然后通过这两张表进行full
2018年9月22日
其他

互联网账户系统如何设计(下篇)?

而如果为交易记账类型,假设这里为乘客使用现金支付车费,则请求被转发至记账子系统,记账子系统根据业务线客户、用户ID、乘客业务用户ID以及tradeCode获取记账规则,完成资金逻辑记账处理。
2018年9月9日
其他

互联网账户系统如何设计(上篇)?

每次产品业务的迭代涉及用户资金逻辑,都不免会影响交易逻辑及账户逻辑本身,但如果业务品类单一,这种迭代及扩展通过硬编码方式多少还能继续支持。但是,如果随着公司业务向多元化发展,问题往往就变得复杂了。
2018年8月29日
其他

业务日志监控工具Sentry介绍

然后,它会显示帮助我们调试的详细信息,比如堆栈跟踪、堆栈本地信息、前面的事件、可能导致问题的提交以及在错误发生时捕获的定制数据。我们还可以在JIRA等项目管理工具中自动开始跟踪问题。
2018年8月25日
其他

支付渠道参数如何设计成路由化配置?

通过上述业务模型的定义,在系统实现时我们需要设计一套配置表,并在渠道对接编码时按照配置逻辑进行接口参数路由动作,从而让系统具备渠道管理的配置能力。
2018年8月19日
其他

移动端支付系统如何设计有效地防重失效机制?

微信支付会通过循环调用的方式主动将支付结果回调给支付系统,再由支付系统回调给外卖业务系统,最后在用户直接感知前由App主动查询外卖业务系统订单支付状态,同时提示用户支付成功或支付处理中这样的信息;
2018年8月14日