概述
支付系统是连接消费者、商家(或平台)和金融机构的桥梁,管理支付数据,调用第三方支付平台接口,记录支付信息(对应订单号,支付金额等),金额对账等功能,根据不同公司对于支付业务的定位不同大概有几个阶段:第一阶段:支付作为一个(封闭)的、独立的应用系统,为各系统提供支付功能支持。一般来说,这个系统仅限于为公司内部的业务提供支付支持,并且和业务紧密耦合。第二阶段:支付作为一个开发的系统,为公司内外部系统、各种业务提供支付服务,支付服务本身应该是和具体的业务解耦合。
支付是电商系统中核心
我们先来看一下用户完成一次购物需要进行那些操作:
通常消费者在手机APP或者网站都会涉及到支付相关的业务场景,用户只需要简单点击支付按钮输入支付密码,就可以完成整个支付过程,那么我就和大家一起来看看一个完整的支付系统有什么功能组成和设计时需要考虑那些问题。
01
支付系统的作用
从上图中我们可以看出真实的资金流向。首先当用户产生支付行为时,资金从用户端流向支付系统,退款时则相反,从支付系统回流至用户端。因此在整个交易过程中用户端与支付系统是双向资金的流动方式。对于支付系统而言,资金有进有出。从支付系统到商户端就比较简单了,在清算完成后支付系统负责将代收的资金结算给商户,通常结算的操作可以在线上来完成(采用支付公司代付接口或者银企直连接口来完成),也可以由公司财务通过线下手工转账的方式来完成,因此这种资金流动的方式是单向的。出于资金安全考虑,大多数公司通常这部分采用线下方式实现。
真实的资金流由支付公司按照约定期限(通常 T+1 )结算到平台公司对公账户中,然后再由平台公司再按照交易明细进行二次清算后结算给对应的商户。
支付系统
一个支付系统需要由哪些功能模块组成
01
完整的支付系统包括如下功能:
-
应用管理: 同时支持公司多个业务系统对接。
-
商户管理: 支持商户入驻,商户需要向平台方提供相关的资料备案。
-
渠道管理: 支持微信、支付宝、银联、京东支付等多种渠道。
-
账户管理: 渠道账户管理,支持共享账户(个人商户)及自有账户。
-
支付交易: 生成预支付订单、提供退款服务。
-
对账管理: 实现支付系统的交易数据与第三方支付渠道交易明细的自动核对(通常T+1),确保交易数据的准确性和一致性。
-
清算管理: 计算收款交易中商户的应收与支付系统收益。
-
结算管理: 根据清算结果,将资金划拨至商户对应的资金帐户中。
02
核心流程
支付系统有几个关键的核心流程:支付流程、对账流程、结算流程
支付流程
支付流程说明
-
用户在商城选购商品并发起支付请求;
-
商城将支付订单通过B2C网关收款接口传送至支付网关;
-
用户选择网银支付及银行,支付平台将订单转送至指定银行网关界面;
-
用户支付完成,银行处理结果并向平台返回处理结果;
-
支付平台接收处理结果,落地处理并向商户返回结果;
-
商城接收到支付公司返回结果,落地处理(更改订单状态)并通知用户。
一般而言支付系统会给商户设置有“可用余额”账户、“待结算”账户;系统在接收到银行返回支付成功信息会进行落地处理,一方面更改对应订单状态,另一方面在商户待结算账户记入一笔金额;该笔金额,系统会根据结算周期从待结算账户--->“可用余额”账户。
退款流程说明
-
用户在商户平台发起退款申请,商户核实退款信息及申请;
-
商户登录支付平台账户/或者通过支付公司提供的退款接口向支付平台发起退款;
-
支付系统会对退款信息校验(退款订单对应的原订单是否支付成功?退款金额是否少于等于原订单金额?),校验商户账户余额是否充足等;校验不通过,则无法退款;
-
支付系统在商户可用余额账户扣除金额,并将退款订单发送至银行,银行完成退款操作。注意:对于网关收款的订单退款,各银行要求不一,有些银行提供的退款接口要求原订单有效期在90或180天,有些银行不提供退款接口;针对超期或者不支持接口退款的订单,支付公司通过代付通道完成退款操作。
对于收单金额未结算,还在“待结算”账户的订单,如果出现退款情况,业务流程和上述流程差不多,只是从待结算账户进行扣款。
对账流程
说明
对账,我们一般称为勾兑,支付系统的对账,包含着两个层面:
-
支付系统内部间的对账,支付系统一般是分布式的,整个支付系统被拆分成了多个子系统,如交易系统、账户系统、会计系统、账户系统,每个子系统在处理各自的业务,系统间的对账,就是以上系统的核对,用于修正内部系统的数据不一致。
-
支付系统与渠道的对账,这里的渠道泛指所有为支付系统提供代收付业务的渠道,如:第三方支付公司、银行、清算中心、网联、银联等。
支付系统与渠道间的对账
系统间的对账比较好理解,这里主要讲支付系统与渠道间的对账。支付系统与渠道间的对账,又包含2个维度:
-
信息流勾对:即业务对账/交易对账,主要是就收单交易的支付信息与银行提供的信息流文件进行勾兑。信息流的勾地能发现支付系统与银行系统间的掉单、两边由于系统间的原因导致的同一笔交易支付金额不一致(可能性很小)或者支付状态不一致。信息流勾兑一般用来恢复掉单数据,可通过补单或者具体系统问题排查解决。
-
资金流勾对:即资金对账,主要就收单交易的支付信息与银行提供的资金流信息进行勾兑。资金流的勾兑能发现支付系统在银行的帐户资金实际发生的变动与应该发生的变动的差异,比如长款(银行多结算给支付系统)和短款(银行少结算给支付系统)。
说了这么多,就出现来4个对账文件,支付系统信息流文件、支付系统资金流文件、银行信息流文件、银行资金流文件。业务对账(勾兑)就是支付系统的信息流文件与银行的信息流文件勾兑,资金对账即支付系统的资金流文件与银行的资金流文件勾兑。
核对的差异处理
1、信息流勾对的差异处理
-
支付系统信息流没有,而银行有的差异,可能是因为支付系统交易数据的丢失、银行的掉单,如果是银行的掉单,由支付公司的运营登录银行网银确认后,做补单处理,并将差异表中该记录核销。
-
支付系统信息流有,而银行没有的差异,此种情况一般不会发生,因为支付系统所有的交易数据都是取银行返回状态的数据。
2、资金流勾对对差异处理
-
支付系统资金流没有,而银行有的差异。可能原因如下:1、银行日切晚与支付系统核心账务系统;2、支付系统账务核心系统与其他系统间的掉单。一旦出现,则会出现长款(即银行不应该结算而实际结算)的现象,对于因日切导致的差异,在第二天的对账中系统会对平,其他原因的,需要技术排查。
-
支付系统资金流有,而银行没有的差异,可能是因为银行日切早于支付系统的核心账务系统,一旦出现,会出现短款(银行应结算而实际未结算)的现象,银行日切导致段差异,会在下一天与银行的勾对中,将此笔差异勾对上,如果是非日切导致的原因,就需要找银行追款了。
总结就是,业务对账,即信息流对账,支付系统的交易流水与银行的交易流水间核对,保障支付交易完整入账。资金对账,即资金流对账,支付系统的入账流水与银行的结算流水间核对,保障银行入账流水与实际入账资金的匹配。
结算流程
在清结算部分,系统按照设定好的清结算规则自动将钱款结算给商户。完善的运营会计体系帮助财务进行精细化核算,提高财务效率。与支付渠道自动进行对账,确保账务正确,在异常情况下能及时定位问题并处理。系统更是能对商户进行个性化的费率配置或账期配置,方便灵活。系统的价值不仅体现在支付清结算方面,同时更是提升了运营管理效率。支付清结算系统可以有效帮助运营、财务、开发以及管理人员。对于运营人员,系统可帮助处理平台的运营工作,包括各类支付管理,商户、会员管理,营销活动的数据统计等,全面提高运营效率。针对财务人员,可以协助完成资金对账、会计处理,出入款管理,账务差错处理等,大部分工作由系统自动处理,减少人工处理,提高资金处理效率。一套灵活便捷的配置后台供开发人员快速调整系统以适应新的业务,并能方便对系统进行维护,如渠道接入、费率配置、账期调整等,提高开发效率。系统提供资金流转过程中各个环节的数据,能够从各个维度进行核算和分析,形成对管理人员的决策支持,从而提高决策效率。
03
关键表设计
04
支付系统要点
在支付系统中,支付网关和支付渠道的对接是最繁琐重要的功能之一,其中支付网关是对外提供服务的接口,所有需要渠道支持的资金操作都需要通过网关分发到对应的渠道模块上。一旦定型,后续就很少,也很难调整。而支付渠道模块是接收网关的请求,调用渠道接口执行真正的资金操作。每个渠道的接口,传输方式都不尽相同,所以在这里,支付网关相对于支付渠道模块的作用,类似设计模式中的wrapper,封装各个渠道的差异,对网关呈现统一的接口。而网关的功能是为业务提供通用接口,一些和渠道交互的公共操作,也会放置到网关中。
支付系统对其他系统,特别是交易系统,提供的支付服务包括签约,支付,退款,充值,转帐,解约等。有些地方还会额外提供签约并支付的接口,用于支持在支付过程中绑卡。 每个服务实现的流程也是基本类似,包括下单,取消订单,退单,查单等操作。每个操作实现,都包括参数校验,支付路由,生成订单,风险评估,调用渠道服务,更新订单和发送消息这7步,对于一些比较复杂的渠道服务,还会涉及到异步同通知处理的步骤。
01
网关前置
支付网关前置是对接业务系统,为其提供支付服务的模块。它是所有支付服务接口的集成前置,将不同支付渠道提供的接口通过统一的方式呈现给业务方。这样接入方就只需要对接支付网关,增加和调整支付渠道对业务方是透明的。 支付网关前置的设计对整个支付系统的稳定性、功能、性能以及其他非功能性需求有着直接的影响。
在支付网关中需要完成大量的操作,为了保证性能,这些操作都尽量异步化来处理。支付网关前置应保持稳定,尽量减少系统重启等操作对业务方的影响。支付网关也避免不了升级和重启。这可通过基于Nginx的LBS(Load Balance System)网关来解决。LBS在这里有两个作用: 一个是实现负载均衡,一个是隔离支付网关重启对调用的影响。 支付网关也采用多台机器分布式部署,重启时,每个服务器逐个启动。某台服务器重启时,首先从LBS系统中取消注册,重启完成后,再重新注册到LBS上。这个过程对调用方是无感知的。
为了避免接口受攻击,在安全上,还得要求业务方通过HTTPS来访问接口,并提供防篡改机制。防篡改则通过接口参数签名来处理。现在主流的签名是对接口参数按照参数名称排序后,做加密和散列,参考微信的签名规范。
02
参数校验
-
所有的支付操作,都需要对输入执行参数校验,避免接口受到攻击。
-
验证输入参数中各字段的有效性验证,比如用户ID,商户ID,价格,返回地址等参数。
-
验证账户状态。交易主体、交易对手等账户的状态是处于可交易的状态。
-
验证订单:如果涉及到预单,还需要验证订单号的有效性,订单状态是未支付。为了避免用户缓存某个URL地址,还需要校验下单时间和支付时间是否超过预定的间隔。
-
验证签名。签名也是为了防止支付接口被伪造。 一般签名是使用分发给商户的key来对输入参数拼接成的字符串做MD5 Hash或者RSA加密,然后作为一个参数随其他参数一起提交到服务器端。
03
路由选择
根据用户选择的支付方式确定用来完成该操作的合适的支付渠道。用户指定的支付方式不一定是最终的执行支付的渠道。比如用户选择通过工行信用卡来执行支付,但是我们没有实现和工行的对接,而是可以通过第三方支付,比如支付宝、微信支付、易宝支付,或者银联来完成。那如何选择合适的支付渠道,就通过支付路由来实现。支付路由会综合考虑收费、渠道的可用性等因素来选择最优方案
04
风险评估
检查本次交易是否有风险。风控接口返回三种结果:阻断交易、增强验证和放行交易。
-
阻断交易,说明该交易是高风险的,需要终止,不执行第5个步骤;
-
增强验证,说明该交易有一定的风险,需要确认下是不是用户本人在操作。这可以通过发送短信验证码或者其他可以验证用户身份的方式来做校验,验证通过后,可以继续执行该交易。
-
放行交易,即本次交易是安全的,可以继续往下走。
05
发送消息
通过消息来通知相关系统关于订单的变更。风控,信用BI等,都需要依赖这数据做准实时计算。
06
更新订单
对于同步返回的结果,需要在主线程中更新订单的状态,标记是支付成功还是失败。对于异步返回的渠道,需要在异步程序中处理。
07
异步通知
其中涉及到调用远程接口,其延迟不可控。如果调用方一直阻塞等待,很容易超时。引入异步通知机制,可以让调用方在主线程中尽快返回,通过异步线程来得到支付结果。对于通过异步来获取支付结果的渠道接口,也需要对应的在异步通知中将结果返回给调用方。 异步通知需要调用方提供一个回调地址,一般以http或者https的方式。这就有技术风险,如果调用失败,还需要重试。而重试不能过于频繁,需要逐步拉大每一次重试的时间间隔。 在异步处理程序中,订单根据处理结果变更状态后,也要发消息通知相关系统。
08
生成交易订单
将订单信息持久化到数据库中。当访问压力大的时候,数据库写入会成为一个瓶颈。
09
交易流水和记账
每一笔交易都需要记录流水,并登记到个人和机构的分户账户上,统计和分析也需要根据交易流水来更新相关数据。 而个人和机构账户总额更新、交易流水记录以及库存的处理,更是需要事务处理机制的支持。 从性能角度, 可以弱化了事务处理的要求,采用消息机制来异步化和交易相关的数据处理。
-
在支付网关前置的主流程中,仅记录交易流水,即将当前的请求保存到数据库中。
-
完成数据记录后,发送MQ出来,记账、统计、分析,都是接收MQ来完成数据处理。
-
涉及到本地资金支付,比如钱包支付,会需要分布式事务处理,扣减账号余额,记账,扣减库存等,每个操作失败,都要回滚。阿里有很不错的分享,这里不详细描述。
-
当交易量上来后,需要考虑交易表的分表分库的事情。分表分库有两个策略,按照流水号或者交易主体id来走。后者可以支持按用户来获取交易记录。我们用的是前者。后者可以走elastic,确保数据库专用。风控,信用和统计所需要的数据,通过MQ同步到历史库里面。作为支付系统最有价值的数据,在存储上做到专库专用,无可厚非,毕竟存储成本还是廉价的。
10
支付路由
支付路由是一个复杂的话题。对支付系统来说,能支持的支付方式越多越好,不能由于支付方式的不支持断了财路。现实中的支付方式多得难以置信。用户随时甩出一张你听都没听说过的卡。如果一个银行卡只有几个用户在用,那针对这个卡开发个对接有点得不尝失。现在第三方支付的爆发,确实给开发支付系统省了不少事。但是公司不可能只对接一个第三方支付,如果这个渠道出问题了,或者闹矛盾了,把链接给掐了,老板还不欲哭无泪。总之,得对接多个渠道。对于交易量大的银行,还得考虑直联。
11
渠道接入
对于支付渠道,首先考虑的是接入哪些渠道。要对接的渠道按优先级有:
-
第三方支付,对大部分应用来说,支付宝和微信支付都是必须的,一般来说,这两者可以占到90%以上的交易量。用户不需要绑卡,授权后直接支付就行。各种平台都支持,性能和稳定性都不错。对于一些特殊业务,比如游戏,企业支付,可以查看一些专用的第三方支付平台。
-
银联,它的存在,极大方便了和银行的对接。和第三方支付主要不同在两个地方一是需要绑卡,也就是用户先把卡号,手机,身份证号提供出来。这一步会折损不少用户。绑卡后,以后的支付操作就简单了,用户只需要输入密码就行。手机客户端不需要像第三方支付那样安装SDK,都在服务器端完成。当然,这是针对快捷支付。网银支付还是挺麻烦的。银联接入也需要ADSS认证。
-
银行:2018年2月9日银监会公布了最新权威数字:一共【4549家】开发性金融机构1家:国家开发银行;政策性银行2家:进出口银行、农业发展银行;5大国有银行:工、建、农、中、交;邮储银行1家;全国性股份制商业银行12家:招行、中信、兴业、民生、浦发、光大、广发、华夏、平安、浙商、渤海、恒丰;金融资产管理公司4家:信达、华融、长城、东方四大AMC;城商行134家;住房储蓄银行1家;民营银行17家,如网商银行;农商行1262家;农村合作银行33家;农村信用社965家;村镇银行1562家;贷款公司13家;农村资金互助社48家;外资法人银行39家;信托公司68家;金融租赁公司69家;企业集团财务公司247家;汽车金融公司25家;消费金融公司22家;货币经纪公司5家;其他金融机构14家。一般对接一个银行预计有3周左右的工作量,大部分银行需要专线接入,费用和带宽有关,一年也得几万费用。不同银行对接入环境有不同要求,这也是成本。
-
手机支付:比如苹果的In-App支付, 三星支付、华为支付等, 这些支付仅针对特定的手机型号, 支持NFC等,根据业务需要也可以接入。
总结
支付系统是一个繁杂的系统,其中涉及了各种错综复杂的业务流程,以上只是简单介绍了支付系统我们能看见的一些问题和设计,还有后续的系统保障没有写出来,没写出来的才是关键部分,比如:支付系统监控(业务监控分类、渠道监控、商户监控、账户监控)文章只是引子, 架构不是静态的,而是动态演化的。只有能够不断应对环境变化的系统,才是有生命力的系统。所以即使你掌握了以上所有的业务细节,仍然需要演化式思维,在设计的同时,借助反馈和进化的力量推动架构的持续演进。
作者介绍:
山哥谈支付系统
============================
支付系统如何进行分布式改造
随着近年来移动支付的兴起 ,如条码支付、声波支付、NFC 近场支付等,随之还产生了聚合支付把多种支付方式聚合在一起,方便人们的使用,移动支付已经渗透到我们生活的每一个角落,不带钱包出门已经没有任何阻碍。这就给传统的支付系统提出了新的挑战,用户量激增,系统容量和性能跟不上了,传统的架构往往以 IOE 技术为主,采用 scale up 方式以更强的硬件提升系统性能和容量,扩容成本将是巨大的。支付机构是持牌机构都是受监管的,对系统稳定性有强要求,传统架构下往往都会用冷备的方式来进行容灾,意味着又要投入一倍的成本,由于数据库主备复制的延时,必须等到数据同步完成才可以切换,容灾切换时间长。进行分布式改造已经刻不容缓。
更多关于传统架构与分布式架构对比请参考《集中式架构与分布式架构比较》
分布式架构在容量、性能、稳定性、成本方面都具有巨大的优势。在高可用方面,核心思想之一是“解决一切单点”,单点容易出现故障,性能方面也可能成为瓶颈,因此需要将单点改造拆分成多个点。垂直拆分能更清晰化模块划分,区分治理,水平切分能解决大数据量性能瓶颈问题,分布式改造主要是将这两者结合起来,对传统架构进行全面的改造。
分布式改造之垂直拆分
垂直拆分就是将原来一个整体的系统按业务模块拆分成多个系统,系统内部数据是自包含的,不会与别的系统共用数据库,系统与系统之间的交互通过暴露和调用服务来实现。那么如何按照业务来拆分呢?
为了方便理解,首先我们来看一下一笔支付过程是如何进行的:
-
商户发起收单请求,经过 API 网关,调到产品层的“在线收单”产品
-
调用收银台选择支付方式,也可能直接进入支付环节,创建交易流水
-
进行支付处理,通过金融交换从银行扣客户帐,记录帐务流水,入商户帐,记录账务流水
-
对交易按照费率进行收费,记录收费的帐务流水。此时会异步触发营销和风控策略
-
日终会异步进行会计记帐(也有同步记会计帐的)、业会核对、清结算和对帐处理
从这个过程可以大概推演出支付系统的一般应用架构:
图:支付系统的应用架构
应用架构定义一个大型软件系统由哪些应用子系统构成,以及应用之间是如何分工和协作的。好的应用架构抽象合理、协作有序、易于扩展、能够复用。有了这个应用架构,我们就可以非常清晰的根据应用架构划分的子系统来进行垂直拆分。
从架构上来说,分为四层:
图:支付系统的分层
渠道层:商户和客户的交易请求的入口。一般会划分以下系统:商户网站、用户网站、无线接入、API 网关。
产品层:通过基础服务层提供的服务组装成具体业务场景功能,对客户、商户运营等人员提供服务。一般会把服务商户的功能划分为商户域,服务 C 端用户的划分为用户域。可以按照这两个域拆分成两个子系统,也可以更进一步根据不同产品特性再拆分,比如商户域中的收单产品、虚拟产品、垂直行业产品。
公共服务层:将各个产品都需要使用的些服务抽像成公共服务。一般会划分:收银台、交易支付、计费等系统。比如说产品层可以通过组装各种交易类型和收费规则形成不同的产品。
基础业务层:支付系统的核心,资金和客户信息的处理都在这里。一般会划分三大子系统:帐务核心、会计核心、会员核心。
其它支撑系统:
网关:负责与银行、银联等金融机构进行资金交换,与外部合作伙伴接入,如渠道拓展商、行业客户等。一般划分:银行接入网关和合作伙伴接入网关。
运营支撑:贯穿于四个层的是运营支撑域:一般会划分运营支撑、安全、风控、营销子系统。
垂直拆分本质上是服务化改造,除了上面讲的按业务拆分,还需要一套分布式服务框架的支撑。
分布式改造之水平拆分
前面讲的垂直拆分只是把系统按业务模块划分到不同的子系统,数据库也分到了不同系统,但没有解决单表大数据量的问题,而水平切分就是要把一个表按照某种规则把数据划分到不同表或数据库里。简单的说就是做分库分表。
在做分库分表之前我们需对数据模型进行分类,分为“流水型数据”、“状态型数据”和“配置型数据”。
-
流水型数据:像流水一样不断增长的数据,各条数据间是独立的。如支付订单、交易流水、帐务流水(入帐/出帐)、会计流水等。
-
状态型数据:代表一个对象当前的状态的数据。如会员信息、客户信息、帐户信息、会计帐。
为什么有会员信息还有客户信息?会员往往是注册在支付平台的用户,一个人可以注册多个会员,但是一个自然人只可能有一个客户信息,一个会员通过实名认证后就关联上了客户信息。无论一个客户注册多少个会员,实名认证后都只有一个客户信息。
-
配置型数据:系统中用作为配置的数据。如产品、手续费率、分支机构信息、支付路由规则、会计科目等。
流水型数据会不断产生,且各条数据间是独立的,天然适合进行分库分表。
状态型数据读写比相当,每一次写操作必须基于前一个正确的状态,可以评估一下数据量的大小,数据量如果大或者要实现单元化架构,也需要进行分库分表,提高并发处理能力,同时方便隔离故障影响。
配置型数据,读多写少,强依赖读,弱依赖写,不要求严格的读一致性,且配置型数据一般数据量不会很大,不需要进行分库分表设计。但是业务处理中往往又需要用到,传统架构的老系统可能使用了一些关联表操作,关联到了配置数据,分库后其它数据与配置不在一个库,不能进行关联表操作,由于配置型数据不要求严格的读一致性的特点,可以将配置型数据加载到分布式缓存里,由业务代码来做“join”。
那么分库分表按照什么规则来拆分呢?通常不会按实体 id 进行 hash 取模的方式来拆分。因为希望同一个用户的数据能够在同一个数据库中,尽量避免产生分布式事务。业界普遍的做法是通过用户维度来进行拆分。由于不同实体 id 的值不同,且不能保证每个实体和请求中都包含用户 id,所以简单的用实体 id 或用户 id 进行 hash 取模将不能保证同一个用户的数据都落在同一个分片。
一种推荐做法是,在用户创建的时候给该用户随机或一定规则(如地区)生成一个两位的分片号 00~99(两位意味着可以分成百库百表,通常够用了),那么在生成与该用户相关的所有实体的 id 的时候,都约定把这个分片号拼接到这个 id 中。在分布式数据访问框架中进行路由选择时,就可以取 id 中的分片号进行路由,而不依赖于用户 id。且在排查问题的时候也非常方便定位数据的存储位置。
下面是一个参考的 id 生成规则示例:
所以数据水平拆分除了需要一个强大的分库分表数据访问中间件,还需要一个分布式序列生成器。当然这个生成器也可以是集成在分库分表数据访问中间件中的一个功能。
那么如果一笔交易涉及多个用户按谁的 id 来拆分呢?比如一笔转账或支付,涉及转出方/转入方或支付方/收款商户。这种情况一般可以按资金转出方来拆分。
分布式改造后带来的问题如何应对
分布式事务产生
由于按用户维度进行了分库分表,可能存在跨数据库的事务,比如说,转账交易中转出方和转入方的账户不在同一个数据库中,这就产生了分布式事务。通常不会用 XA 协议来解决,因为 XA 协议锁资源性能太差,通常是通过 TCC 柔性事务来解决。具体可以参见进阶阅读《分布式事务综述》。
跨表查询如何解决
由于分库分表后,不能进行跨库的连表查询,原来的一些很常见的查询操作变得很麻烦。对于不是以用户为维度的汇总查询也非常麻烦。比如说支付交易流水是按发起方用户(支付方)进行拆分的,用户需要查询自己的账单很容易。但是商户要查询账单就比较麻烦了,要去所有的库里遍历、汇总、分页。也非常耗系统资源。所以一般会做一些数据冗余,例如专门实现一个账单系统,通过消息队列异步将用户的交易流水同步过来,T+1 跑批再按商户维度进行拆分,并生成商户账单。查询帐单都从帐单系统中查询。
还可以通过异构索引来查询和做 OLAP 分析,异构索引就是将数据同步到 ElasticSearch,利用 ES 的强大索引能力来做查询和分析,为了使业务更容易使用,可以利用数据访问代理层来屏蔽底层是路由到数据库还是路由到 ES。
如何进行数据同步
企业都有做大数据分析的需求,需要将数据同步大数据平台,如 Hadoop。分库分表之后,数据同步会比较复杂,毕竟之前是单表同步到 Hadoop 比较简单,但是 100 张表同步到 Hadoop 里会复杂一些。这时就需要设计一套专门的数据模型管理平台,数据模型、分库分表规则等由这个平台来管理,当需要使用数据的时候通过(应用/逻辑表)维度订阅数据即可,不用单独订阅物理表。不仅是数据同步,凡是有业务需要用到各种数据,都可以通过这个平台来订阅,帮助企业数据业务快速发展。
分库分表后批处理任务怎么处理
批处理任务,比如有日终对账、清算、生成账单等,原来在一个数据库中的时候,由一个应用 Server 去数据库中捞取流水就可以了。但是分库分表后流水都落在很多库里,一个 Server 去每个库里遍历显然不是一个很好的办法,且不能充分利用机器资源,提高批处理效率,甚至由于处理的数据量太大在日终低峰期内根本无法完成任务。
前面提到各条流水数据之间没有关联的,完全可以并发的进行处理,每个 Server 捞取一个分片的数据进行处理。那么就需要有一个很好的调度系统来协调,可以采用三层调度的方式。
图:三层调度示意图
-
第一层 split:把任务按照分片规则拆分成多个 Load 任务,并发送到集群中的 Server 去执行。
-
第二层 load:每个 load 任务捞取一个分片的数据,逐条创建 execute 任务,并发送到集群中的 Server 去执行。注意:捞取数据要进行流量控制以免数据量太大把集群打满。
-
第三层 execute:执行具体的一条数据的逻辑。
三层架构并不是说一定都需要三层,可以根据业务逻辑来定制只有两层也可以。
如何进行数据扩容
通常可以采用“预分配”的方式来做,即一开始就按一个比较长期的容量来规划分片数,比如百库百表。但实际上一开始并没有这么大的量,所以实际只有两个数据库 Server,在这两个 Server 上分别建 50 个 schema,逻辑上仍然是 100 个分库,物理上只有 2 个数据库 Server。当容量不够的时候,为了保证数据的均衡,通常会采用成倍扩容的方式,再加两台数据库 Server,然后分别迁移 25 个 schema 到这两个数据库 Server 上,数据也搬过来。由于数据同步有延时,全量数据同步完成后,两边的 schema 都禁写,待增量数据同步完成后打开新的 schema 写,会产生短暂的部分用户交易失败,重试一下即可,在低峰期做迁移,产生小范围失败一般是可以接受的。由于逻辑分片数没有变化,扩容成本比较低。通常不会用改变分片规则的方式来扩容,因为改变分片规则需要进行数据重新分布,成本和风险巨大。
如何进行容灾
-
同城容灾:通常可以同城多机房部署应用,数据库只有一个机房处于 Active 状态,所有机房的应用都连这个机房的数据库,另一个机房的数据库为备库,进行主备复制,当备机房发生灾难时业务不会中断,但业务会跌一半,当主机房发生灾难时,数据库切换备库,会有短暂的业务中断。
-
异地冷备:应用也是异地多机房部署,由于异地网络延时不可忽略,异地备机房是处于 standby 状态,正常是没有流量的,冷备机房采用数据库主备同步的方式同步数据,这种方式灾备切换时间长,成本投入高。
-
异地多活:应用采用异地多机房单元化部署架构,每个机房的应用都是可以提供服务的,单元内是自包含部署全量应用,每个单元服务多个分片的用户,单元化架构可以参考《素描单元化》。由于异地网络延时是不可忽略的,数据层的容灾方案也是分“流水型”、“状态型”、“配置型”数据采用不同的容灾策略。具体可参考《分布式系统数据层设计模式》。
如何更好的排查和分析问题
分布式改造后整个系统架构已经是服务化了,原来通常可以通过查本地日志来定位问题。但现在一个交易由若干个系统协同完成,我们需要一套分布式链路跟踪系统或 APM(应用性能管理)系统来协助我们看清整个系统的全貌,分析排查问题。那么如何进行分布式链路跟踪呢?可以通过 OpenTracing 标准对整个分布式架构中的中间件和应用进行埋点或自动植入探针实现。
总 结
分布式架构有着海量、成本、稳定、速度的优势,但它也不是银弹,分布式改造是一个较为复杂的工程,既需要熟悉业务,能够设计出整个系统的业务架构,按照业务架构来进行垂直拆分,又需要熟悉数据模型,区分“流水型”、“状态型”、“配置型”数据,根据不同类型数据的特点将它他按用户维度进行拆分,还需要熟悉分布式中间件的运用。分布式中间件在整个分布式架构中起着至关重要的作用,将技术构架与业务结合起来。蚂蚁金服通过多年金融级架构的演进,经过多年双十一大促的验证,已经形成了一套业界领先的金融级分布式架构,请参考《金融级分布式交易的技术路径》。
=====================================
从0到1实现一套聚合支付系统
大家好,我是来自盒子科技研发部支付线刘恒,目前主要是负责公司的一个聚合支付系统的研发工作。今天主要是讲一下我们聚合支付系统从2016年年初到现在技术演变。
首先我会从那三个方向,第一是聚合支付的介绍,聚合支付在我们公司它承担一个什么样的地位,第二是在我们公司有什么样的使用场景。第三是从公司开始做聚合支付最开始的版本是什么样子的,在这个版本之上,我们做了什么样的优化,然后到了现在发展成什么样的架构。
01
聚合支付的介绍
_____
首先从第一个主题讲什么是聚合支付,聚合支付主要是就是一个将所有的第三方支付,通过借助形式融合在一起,相当于对接一个支付接口,就可以使用各种支付的场景,就比如说各位有可能去那种超市便利店去买东西,贴着一个码,码上有什么微信支付,支付宝支付,还有一个京东QQ各种支付。然后我们公司也有一个,就是一个好哒,相当于这个用户就是图上两个男生,然后扫橙色的那个二维码,所以我们公司做了一个好哒立牌。
它主要是针对一个微小商户进行一个收款工具,让商家他那边会有一个好哒商户通,第一个可以实时的收听语音报告,当前用户付款多少钱,第二个就是他可以去实时查看账单,了解当天的营业额。
还有一个产品就是我们公司的一个pos机。这个主要是一款生态pos,它里面不仅继承了我们一个我们这个具备支付系统提供的服务,就比如微信支付宝,它们还集成了一个刷卡的功能,就是磁条卡芯片卡,还有各种支付方式。
这次我们讲的聚合支付,只是涉及到交易流,不涉及到资金流,资金流是其他项目组负责。
02
1.0系统
_____
好,进入项目背景。
第一个就是工期短,基本上所有的项目都会遇到,天天都在赶工程。
我们是从2016年过年前一周,然后忽然被拉入一个群,说是有个项目要做一做,当时老大让一周上线,
第二是业务不熟。不知道聚合支付到底做什么事情,它的支付流程是什么样的?虽然说之前做过支付相关业务,但是每个公司支付业务是完全不一样的。当时做微信支付宝,微信APP ID是什么东西还不知道,所以说就在这种情况下开始着手,还有就是一个当时的交易量,当时的交易量是只有前端的一两个产品在使用,每天的交易笔数也很小,就几千笔。
第三个就是人员的缺乏,因为当时就做系统研发,只有我和另外一个新同事。
就在这种背景下,我们就搭建了第一套系统架构,即虚线圈住的,我负责交易前置,同事负责交易网关,当时就直接操作DB没有做任何的其他的优化。
当时就做这样一个简单的架构,第一个开发比较快,直接拿需求进行改代码,方便测试以及上线。当时是2016年3月份4月份就上线了,也很快。后来就是在经过了三四个月交易量比较猛增的情况下,就发现这个系统感觉各种瓶颈就出来了。
• 渠道的隔离,因为当时对接了几个渠道,特别渠道不稳定的话,比如资源不可用、网络问题,导致超时,这样就会把所有渠道交易全部影响,造成级联反应,导致整个服务交易链路不可用,影响比较严重。周末别人都可以在家好好休息,但是我们支付研发不行,每天都是随时关注手机,因为说不定哪个渠道就出问题了,立马要处理。而且系统哪边挂了之后立马要赶紧联系。所以说这个渠道隔离放在第一位首要的。
• 接口膨胀,特别涉及到某些相似的业务,就比如说那个消费、撤销、退款接口,就每个业务类型都有这几个接口,随着业务的发展,也不好维护,开发每次来个需求都要去考虑,到底是改哪个接口,要不要都改。
• 动态扩容。因为聚合支付很多交易都是异步的,用户下单时,我们会立即返回就下单成功,或者下单失败,但是这个交易有没有消费成功,我们需要设置定时的任务去查询最终付款结果。
定时调度,它需要定时、定点、定量的去拉取一批订单进行处理,如果拉取的数据太多,内存直接爆了,拉取太少,有很多交易得不到执行。在分布式环境如何充分提升并发的前提下充分使用机器的资源变得越来越紧迫。
• 配置分散,传统方式是将配置文件存放在每一个节点,每次升级都需要运维手动改。风险较高而且相当不好维护。
03
2.0系统
_____
在这个前提下,我们开始着手设计2.0。当初有几个大的方向:
• 稳定:支付系统的根基
• 支付体验:用户使用支付功能时感知零延迟
• 低耦合:模块之间减少依赖,需求变动风险控制在最小范围
在这个过程中也是试了很多种方案,要么程序复杂,你写完的话可能只有自己懂,后续不好维护;要么性能跟不上去。所以我们也尝试了各种方案,最后演变为如下系统架构。
首先将服务划分为三条线,上面绿色的,和中间那个红色的和最下面一条橙色的。绿色的就是我们把交易核心、交易网关独立出来。任务作业和那个查询网关独立部署。这两条业务线通过MQ进行解耦,然后我们再独立查询服务,对前端业务仅仅提供一个流水查询功能而已。
业务流程如下:
业务发起一笔消费,首先进入支付核心初始化流水、风控风险识别、渠道路由、渠道网关报文组装、上送、渠道应答。异步交易发送消息至MQ集群,任务作业监听消息,put缓存,定时任务拉取进行状态查询,业务方通过查询服务查看该笔交易支付状态
前置优化水平方向
• 接入层:将共性的接口统一。比如说下单,所有的业务,不管微信支付,还有其他的全部归为下单,具体的业务,通过一个serviceId参数进行识别
• 服务层:共性逻辑,也就是核心逻辑全部抽离出来,然后进行统一下沉,作为底层服务,上层业务全部通过serviceId配置化实现,这样的话尽量去少改动核心业务逻辑。
• 缓存层:随着交易量的增长,特别是在第一代的时候,里面很多业务查询都是直接操作DB了,对DB有很大的性能影响。所以我们就是在DB之上将所有消费交易信息全部缓存,后续所有的操作查询和更新全部操作缓存层主要为了提升了服务的性能。
前置优化垂直拆分:
• 核心交易:负责交易的核心链路,用户感知最明显。比如支付失败,用户立马能知道,立马就会投诉或者打电话给客服,该模块也包含退款等业务。
• 任务作业:将处理中的交易进行状态同步,和核心交易通过消息解耦
• 查询服务:仅仅是对公司内部提供一个交易状态的查询功能
任务作业内部查询策略设计为两个队列、一个批处理
• 内存队列:基于DelayQueue设计的延迟队列,通过制定算法策略,就是比如说延迟十秒、间隔五秒,或者是很多银行使用2的N次方进行查询。
该队列主要是针对单笔交易执行快速状态同步,提升用户体验。
• 缓存队列:基于我们公司Codis缓存集群,结合分布式调度框架Elastic-Job设计。主要是针对状态延迟的订单,进行批量状态同步
• DB批处理:也是结合Elastic-Job设计,主要是提供人工干预的入口,当渠道延迟比较长、或者渠道异常的情况下,执行批量状态同步
分片策略:
• 任务分片:目的在于把一个任务分散到不同的机器上运行,既可以解决单机计算能力上限的问题,也能降低部分任务失败对整体系统的影响。elastic-job并不直接提供数据处理的功能,框架只会将分片项分配各个运行中的作业服务器(其实是Job实例,部署在一台机器上的多个Job实例也能分片),
PS:开发者需要自行处理分片项与真实数据的对应关系。框架也预置了一些分片策略:平均分配算法策略,作业名哈希值奇偶数算法策略,轮转分片策略。同时也提供了自定义分片策略的接口。
• 数据分片:订单号取模存储(zset)
数据结构:
• 有序集合(zset):按照分片逻辑,将订单号取模,存放至对应的队列中
• string:交易明细序列化存储
设计思路:
1. MQ消费者(作业节点),接收到消息后,将数据存放在缓存
2. 作业节点根据分片项、score范围,定时从对应的缓存队列中获取指定数量的订单号
3. 业务循环处理,根据订单号再去缓存中获取对应的详细信息
4. 执行查询逻辑
注意事项:
zset元素数据过期,需要业务自己处理,可以单独建立检测机制,也可以每次执行业务时执行判断,过期则移除,不然集合会越来越大。
• 渠道隔离:在高并发访问下,系统所依赖的渠道稳定性对系统的影响非常大,依赖有很多不可控的因素,比如网络连接变慢,资源突然繁忙,暂时不可用,我们选在知名的容错开源框架Hystrix,隔离方案选择thread。
• 查询网关:在交易系统中,查询业务量一般时支付业务的6倍,甚至更高,这样对查询服务性能就会有更高的要求。减少对核心交易影响,提升稳定性。
通道商户缓存:通道信息(机构号、商户号、**等)属于静态信息,在初次使用时存放至分布式缓存系统中(设置有效期,防止僵尸数据),同时增加手动修改的入口,方便人工干预。
• 千里之堤毁于蚁穴:我们用容错的方式就是让这种蚁穴不要变大,在依赖的服务不可用时,服务调用方应该通过一些技术手段,向上提供有损服务,保证业务柔性可用。
• 线程池资源隔离:Java的Servlet容器,无论是Tomcat还是Jetty都是多线程模型,都用Worker线程来处理请求。当业务请求打满Worker线程的最大值之后,剩余请求会被放到等待队列(或者拒绝掉),如果等待队列也塞满之后,那这台Web Server就会拒绝服务。
如果你的服务是QPS较高的服务,那基本上这种场景下,你的服务也会跟着被拖垮。假如上游服务也没有设置合理的超时时间,故障就会扩散。这种故障逐级放大的过程,就是服务雪崩效应。
我们采用容错框架Hystrix来解决此问题。通过Hystrix命令模式,将每个类型的业务请求封装成对应的命令请求。每个命令请求对应一个线程池,创建好的线程池是被放入到ConcurrentHashMap中。
注意:尽管线程池提供了线程隔离,也必须要有超时设置,不能无限制的阻塞以致于线程池一直饱和。
Hystrix线程监控
实时展示当前各个业务线程池资源使用情况,研发人员可以以此为参考,确定资源是否够用、是否需要升级机器资源等。
2.0之后我们是全面对接我们公司监控平台,主要从以下几点进行监控:
• 节点耗时监控:如说哪个时间点、哪个节点耗时比较慢,通过百分比的形式,可以比较直观的看出问题。
• 成功率的监控:折线图定时刷新数据,将各个时间点的交易记录数、成功笔数、失败笔数进行汇总计算,渠道接口异常时可以第一时间发出告警
• 应答码监控:应答码TOP排行榜,方便研发分析数据,提前将问题通知给渠道,减少后续可能出现更大的问题;部分应答码重点监控,通过设定告警阀值,超过阀值短信及电话告警,研发第一时间接入处理,减少可能造成的损失。
• 邮件巡检报告:用于第二天研发进行数据分析。
以上就是盒子科技聚合支付系统演变的大致过程,在 2017年的到现在没有出现任何技术故障和业务故障,没有造成一笔长款、短款的出现,系统具备良好的伸缩性,能够保证公司近两年业务的快速发展。
04
下一步需要做什么
_____
那么在系统稳定的基础之上,下一步我们还需要做哪些事情呢?
• 全链路的监控:我们现在链路监控只是从前端到后端有一个请求的跟踪号,但是这个都分散在我们业务日志里面的。所以说我们下一步就准备做一个全链路的监控,就相当于把每一个每笔交易,它具体在哪个时间点在哪个机器上,然后在哪个渠道,然后它状态做的什么变更,做一个完整的记录,通过一个可视化的界面提供出来,方便客服、运营等其他协作部门使用。
• 智能路由:遇到渠道异常、临时停用渠道等等情况下,需要将用户切换至其他渠道,目前都是人工通过拉取数据手工操作的,所以下一步我们就想如何让我们的路由更加智能。
• 动态分片:主要包括数据分片、任务分片,业务量持续倍数增长的情况,各个环节的分片策略如何做到自动化实现,充分使用各个机器的性能。(本文完)
================================
金融级分布式交易的技术路径
移动互联网、大数据与云计算作为新的基础设施,催生了新的互联网经济,也正在推动各行各业的升级。在过去十多年中,金融服务飞速发展,移动支付支撑了零售业线上线下的变革,基于大数据的信贷服务支持了无数小微企业的创业创新,老百姓可以随时随地享受曾经高门槛的理财、保险等金融服务。以普惠服务为目标、数据与技术驱动、新型信用体系为基础的新金融已经成为新经济的基石。
伴随着蚂蚁金服在新金融领域的探索,蚂蚁金服技术团队也在金融技术与架构领域不断开拓。从 2005 年每秒处理 1 笔交易到 2015 年双十一每秒处理 8.59 万笔交易,从单一的支付到覆盖微贷、理财、保险、信用、银行等,通过十多年的探索与实践,我们形成了一套包含金融级分布式交易、分布式大数据分析与决策等在内的完整架构与技术体系。
在本文中,我们将与大家交流金融级分布式交易相关的实践与体会。
金融级系统的关键目标
如果将建造系统比作盖楼的话,建一个常规的系统要先立稳四根柱子:高可用、安全、性能、成本。但要建一个移动互联网时代的金融级大厦,除了上述四根柱子需要更加牢固,还需要加上两根柱子:资金安全与数据质量。这六根柱子,是我们在架构蚂蚁金服的每一个系统时的首要目标。
具体来说,我们对一个金融级系统有以下关键目标:
高可用:具备 99.99% 以上的高可用性。系统能够容忍各种软硬件设施的故障,可以在服务不中断的情况下进行升级,在严苛的应用场景下保证承诺的服务质量,容忍各种人为失误。对于关键系统,还需要具备异地容灾能力。
安全:具备多层次检测、感知与防御各类安全攻击的能力。系统有能力实时、精细地分析系统行为与数据流发现异常,必要时可以快速调集资源阻断大规模、有组织的攻击。
性能:对于实时交易业务,要求极快的响应时间与极高并发能力。对于批量业务,要求极大的吞吐量。尤其重要的是,系统必须具备很强的可伸缩性与弹性,在需要时可以快速调集资源应对突发的业务量。
成本:在满足高可用、安全与性能的前提下,成本是一个重要约束。我们将单笔交易的平均处理成本(月交易总笔数/月成本)、以及峰值交易的处理成本(每提升 1000 交易 TPS 需要追加的成本)作为两个关键指标去持续优化。除了必须在基础软硬件与系统关键链路上做极致的优化外,灵活的资源调度与按需伸缩能力是优化成本的关键。
资金安全:这是金融级系统与常规系统的一个关键差异。要做到资金处理绝对不出差错,需要交易与数据具备强一致性,需要在任何故障场景数据不丢不错,需要具备准实时的交易资金核对能力,需要在异常场景下有精细化熔断与快速恢复能力。
数据质量:数据质量是金融服务质量的基础。数据从采集、生成、流转、存储、计算、使用需要经历很多环节,要确保经过这么多环节后,数据依然是准确、完整和及时的,需要系统具备全链路的数据质量管控与治理能力。
金融交易系统是否可以走分布式路线?如何基于分布式的思想与技术达到以上 6 个关键目标?接下来,我们就以蚂蚁金服的实践为基础,分享对这个问题的观点。
分布式金融交易架构与技术
1
强一致的微服务:微交易架构
微服务是一种广泛应用的分布式架构。通过将系统分解为单一职责、高内聚、松耦合、独立部署、自主运行的“微“服务,可以极大提升系统的灵活性与扩展能力。但由于每一个微服务是自包含的数据与计算单元,当一个有严格一致性要求的交易,被分布在很多节点上执行时,如何保证数据与服务处理达到金融级的强一致性,成为一个难题。尽管可以用支持分布式事务的数据库或数据中间件来保证数据分布时的一致性,但解决不了当服务分布时的一致性问题。由于分布式事务对资源加锁的时间长、粒度大,也制约了系统的可伸缩性与高可用性。
为了解决这个难题,我们提出一种使微服务具备强一致性的微交易架构。在这种架构中,涉及到交易操作的微服务具备事务属性。一个微交易提供三种操作TCC(Try-Confirm-Cancel),其中 Try 操作负责业务检查与资源预留,Confirm 操作负责实际操作,Cancel 操作负责释放预留的资源。一次完整的交易由一系列微交易的 Try 操作组成,如果所有的 Try 操作都成功,最终由微交易框架来统一Confirm,否则统一 Cancel,从而实现了类似经典两阶段提交协议(2PC)的强一致性。但不同于 2PC,微交易架构力求高效与可伸缩。TCC 三个操作都是基于本地事务的短事务,Try 操作只预留必须的业务资源,比如一笔交易涉及10元钱,仅预留账户中的 10 元钱,而不是锁定整个账户,TCC 协议在提交时,也没有单独的 Prepare 阶段,将提交协议的成本降到最低。
从 2008 年初上线至今,微交易架构已经应用到蚂蚁金服的各种金融业务场景,经历过历次大促高峰考验,证明这套架构与技术的可行性。
2
请金融级分布式数据库: OceanBase
目前,主要商业数据库本质上是单机系统,其容量、性能和可靠性均依赖于单个或少量高性能服务器与高可靠存储的组合,成本高昂且扩展困难。尽管通过运用微交易架构,可以将对数据操作的压力分拆多个数据库,解决了水平可扩展的问题,但数据库本身的性能、成本与可靠性依然是一个难点。因此,阿里巴巴与蚂蚁金服从 2010 年起,开始研发专门的金融级分布式数据库 OceanBase。
OceanBase 在以下几个方面,对传统数据库架构进行了突破:
高性能:数据库的一个显著特征是总数量比较大,但每天变化(增删改)的数据只是总数据量的很小一部分。因此 OceanBase 将数据划分为基线数据和修改增量。基线数据即数据库在某个时间点的一个快照,存放在每台 OceanBase 服务器的硬盘中,修改增量即快照点之后的增删改数据,相对比较小,通常存放在每台 OceanBase 服务器的内存中。通过这种方式,使得增删改操作基本都在内存中进行,从而获得接近内存数据库的事务处理性能;
强一致:经典的主库+备库方式的数据库,很难兼具高可用与强一致能力。为了解决这个问题,OceanBase 使用多数据副本(>=3)投票协议,对于每个写事务,OceanBase 只有在事务日志(redo log)到达超过半数服务器后,才应答客户。这样当少数服务器(例如 3 台中的 1 台,或者 5 台中的 2 台)异常时,剩下的服务器至少有一台有事务日志,保证了数据库不因为少数服务器故障而导致数据丢失;
高可用:关键业务的数据库必须达到 99.999% 的可用性,服务器故障、机房或网络故障都不能导致数据库不可用。OceanBase 通常由分布于多个机房(3 个或以上)的机群组成,每个机群有完整数据,其中一个机群作为主库对外提供读写服务,其余机群作为备库,接收主库的事务日志和回放日志。当主库故障时,剩下的机群会立刻自动发起投票选举,选出新的主库,新主库从其他机群获得可能存在的最新事务日志并回放,完成后对外提供服务。
目前 OceanBase 已经稳定支撑了支付宝的核心交易、支付与账务,支撑了网商银行的核心系统,经历了多次“双十一”的考验,形成了跨机房、跨区域部署的高可用架构,并在日常运行、应急演练和容灾切换中发挥了重要作用。
3
异地多活与容灾: 单元化架构
“两地三中心”是一种在金融系统中广泛应用的跨数据中心扩展与跨地区容灾部署模式,但也存在一些问题:在扩展能力上,由于跨地区的备份中心不承载核心业务,不能解决核心业务跨地区扩展的问题;在成本上,灾备系统仅在容灾时使用,资源利用率低,成本较高;在容灾能力上,由于灾备系统冷备等待,容灾时可用性低,切换风险较大。
因此,蚂蚁金服没有选择“两地三中心”部署模式,而是实现了异地多活与容灾模式。异地多活与容灾架构的基础是对系统进行单元化。每一个单元可以认为是一个缩小规模的、包含从接入网关、应用服务到数据存储的全功能系统。每个单元负责一定比例的数据与用户访问。单元有以下关键特性:
自包含性:比如用户的一次账户充值交易,涉及到的所有计算与数据都在一个单元内完成;
松耦合性:跨单元之间只能进行服务调用,不能直接访问数据库或其它存储。对于一些必须跨单元的交易处理,比如分属于两个不同单元的用户之间的转账交易,跨单元的服务调用次数尽可能少,在业务与用户体验允许的情况下尽量异步处理。这样,即使两个单元之间相距上千公里,也可以容忍跨单元的访问时延;
故障独立性:一个单元内的故障,不会传播到其它单元;
容灾性:单元之间相互备份,确保每个单元在同城和异地都有可在故障期间进行接管的单元。数据在单元间的备份方式,我们以 OceanBase 提供的多地多中心强一致方案为主。
通过单元化架构,能够将一个大规模系统分拆成许多个相对独立的小规模系统,每一个单元系统可以部署到任何地区的数据中心,从而实现了灵活的异地多数据中心部署模式。系统的主要伸缩模式变成单元的增减,但一个单元内部的规模与复杂性不变,降低了系统的复杂性。单元之间的故障隔离,降低了软硬件故障的影响面。“活”的单元和跨单元的快速切换能力,使同城异地的容灾处理更为简单高效。
目前,蚂蚁金服的核心系统已经分布在上海、深圳、杭州等多个城市的多个数据中心,核心交易流量分布在各个数据中心,并且可以进行调度与切换。通过异地多活,系统可以在全国范围内任意扩展,服务器资源得到了充分利用,提升了系统应对地区级灾难的能力。
4
按需伸缩:弹性混合云架构
每年,支付宝系统都要应对双十一、新春红包等活动的极高交易量。尽管单元化架构让我们具备应对峰值的能力,但要降低高峰期的资源投入,系统还需要具备按需伸缩的能力。
我们解决这个问题的方法是,活动前,在云计算平台上快速申请资源,构建新的单元,部署应用与数据库。然后将流量与数据“弹出”到新的单元,快速提升系统容量。当活动结束后,再将流量与数据“弹回”,释放云计算平台上的资源。通过这种方式,可以大大降低资源采购与运行成本。
弹性操作,需要在流量、数据与资源之间协调一致地操作,尤其是有状态的数据的弹性操作是最困难的,需要不中断业务,也需要保证数据的一致性。这些操作如果依靠运维人员人工执行会十分复杂低效,需要架构、中间件与管控系统的支持。
弹性混合云架构与技术在实践中有以下一些关键点:
1. 通过统一资源调度,灵活地申请与分配计算、存储与网络资源,创建单元,快速部署数据库、中间件与应用;
2. 通过中间件,将应用与基础设施充分解耦,无论流量、数据与资源如何分布,应用系统不需要改变;
3. 通过分布式架构与数据规范,以及中间件支持,保证所有请求、服务、数据、消息等都有全局唯一的 ID 和一致的 ID 编码规则。根据 ID,从接入网关、服务中间件、消息中间件、数据中间件等都能够正确地路由服务请求与数据访问;
4. 通过统一管控平台,将高层的弹性操作,翻译成各个组件的部署与配置指令,并且统一调度执行,使操作协调一致、精准高效。
基于弹性混合云架构,2015 年双十一,支付宝有 10% 的支付流量运行在阿里云计算平台上。2016 年双十一,我们计划将 50% 的高峰期支付流量运行在阿里云计算平台上,带来成本的极大优化。
未来展望与期待
蚂蚁金服的实践证明了在金融级中间件、数据库和云计算平台的支持下,分布式架构可以完全胜任复杂、高要求的金融级交易,并且给出了一种可供参考的技术架构与实施路线。
未来,蚂蚁金服依然会在金融级分布式架构与技术方面深耕与拓荒。在这一领域,我们给自己提出两个新的重大命题:
1. 如何处理每秒 1 亿笔交易:万物互联时代,无处不在的交易终端和无数新的交易场景,会继续带来金融交易量的指数型增长。什么样的架构与技术,可以处理万物互联时代的天量交易,是需要未雨绸缪去攻坚与突破的;
2. 将金融级分布式架构与技术变成“普惠”的云计算服务,为千千万万金融服务机构服务。为了实现这个目标,蚂蚁金服和阿里云共同提出了“蚂云计划”,共建新一代的金融云平台,未来服务全球 5 万家金融机构,共创全球化的普惠金融。
中国已经在金融服务创新上处于世界领先,新金融需要新技术作为底盘与引擎,这是中国金融技术的挑战与机遇。蚂蚁金服期待与中国金融业的专家一起,共同创造未来的新金融技术,为世界技术做出更多中国的贡献。
========================
1.异地多活与容灾: 单元化架构
2.布式改造是一个较为复杂的工程,既需要熟悉业务,能够设计出整个系统的业务架构,按照业务架构来进行垂直拆分,又需要熟悉数据模型,区分“流水型”、“状态型”、“配置型”数据,根据不同类型数据的特点将它他按用户维度进行拆分,还需要熟悉分布式中间件的运用。
3.以上只是简单介绍了支付系统我们能看见的一些问题和设计,还有后续的系统保障没有写出来,没写出来的才是关键部分,比如:支付系统监控(业务监控分类、渠道监控、商户监控、账户监控)文章只是引子, 架构不是静态的,而是动态演化的。只有能够不断应对环境变化的系统,才是有生命力的系统。所以即使你掌握了以上所有的业务细节,仍然需要演化式思维,在设计的同时,借助反馈和进化的力量推动架构的持续演进。
4.从0到1实现一套聚合支付系统。对外的商业系统。
5.第一层 split:把任务按照分片规则拆分成多个 Load 任务,并发送到集群中的 Server 去执行。
第二层 load:每个 load 任务捞取一个分片的数据,逐条创建 execute 任务,并发送到集群中的 Server 去执行。注意:捞取数据要进行流量控制以免数据量太大把集群打满。
第三层 execute:执行具体的一条数据的逻辑。