在美联支付系统升级到2.0架构(支付体系架构演进-上)期间,我们针对电商平台特性,比如大促时支付链路峰值为日常的百倍以上等等特性,做了哪些容量和稳定的提升?
下面我们以支付核心链路(图1)为例,谈谈如何提升支付平台的容量和稳定性。
图1 支付核心链路
一、容量提升
针对于电商特性,我们对支付平台的容量提升主要是从以下几个方面优化:
核心链路分库分表:全链路水平扩展
服务调用异步化
热点账户问题优化
事务切分
1.1 核心链路分库分表:全链路水平扩展
目前所有的应用服务都是无状态,理论上应用服务可以做到无限扩展,目前最大的瓶颈是在DB。性能容量的提升,关键在于DB的容量。基于这个原因,我们对整个平台的DB做了水平的拆分。
在全平台水平扩展的过程中,我们以核心链路为例,从交易核心、支付核心、账务核心、渠道网关等系统全部做了数据库的水平拆分。基于交易核心、支付核心、渠道网关等系统,前面介绍过,我们抽象了各种基础模型,数据都是基于一张主表存储,因此水平拆分基于该主表即可。
得益于美联自研的数据库中间件Raptor,我们实现链路的分库分表。同时,也基于全局统一的sequence生成器,保持了所有分片内的主键id唯一性。
图1.1 支付核心链路分库分表
1.2 服务调用异步化
支付体系2.0升级之后,单体应用拆分为数十个服务。系统的拆分和服务化,其实带来了更多的系统依赖。相对于之前的单体应用,从方法级的调用方式变更为RPC服务调用,网络耗时 & 同时网络的稳定性等因素也是需要考虑的问题。基于这些考虑,非强实时的服务调用,异步化是最佳的解耦方式。同样,在核心链路里,我们也做了各种各样的异步化优化,进而提升整体的链路性能,满足电商平台独有的性能特性要求。
我们从几个点来看下如何对支付系统做异步处理:
1.2.1 支付消息报
基于数据库事件中间件 Pigeon & 消息队列Corgi,我们实现支付消息报。如图1.2所示,支付消息报基于交易核心数据,聚合支付核心的支付数据,最终生成支付消息报。通过这种方式,将原本需要在交易核心或者支付核心调用下游业务方,或者下游业务方实时查询的方式,转变为下游业务方通过接受消息的推送来获取数据,从而达到了业务的解耦。同时,也简化了业务方的数据获取复杂度。
图1.2 支付消息报架构图
目前支付消息报已经接入了10多个业务场景,例如满返活动,支付成功短信通知,风控所需的支付数据等等,并在持续不断的增加中。
1.2.2 外部支付异步化
在外部支付中,经常会碰到这种情况,需要服务方与第三方支付交互,获取预支付凭证,如图1.3所示。这种同步调用的情况下,由于需要跨外部网络,响应的RT会非常长,可能会出现跨秒的情况。
由于是同步调用,会阻塞整个支付链路。一旦RT很长且QPS比较大的情况下,服务会整体hold住,甚至会出现拒绝服务的情况。
图1.3 同步调用三方支付
基于这个问题,我们对这种获取预支付凭证的方式进行了改进,详见图1.4。
图1.4 异步调用三方支付
通过独立网关渠道前置服务,将获取的方式分为两个步骤:
1)针对支付链路,只是请求到渠道前置拿到内部的支付凭证就结束了。
2)针对外部请求,由渠道前置异步向三方支付发起请求。
那么基于这种方式,与三方支付的同步交互仅仅会阻塞渠道前置。密集型的io & 低cpu系统,渠道前置的并发值可以设置的非常大。
1.2.3 异步并行
支付平台服务化之后,核心链路上的服务多为IO密集型,这里我们以收银台渲染为例,见图1.5。
图1.5 串行模式下的收银台渲染
一次收银台渲染,串行的调用各个服务来进行用户信息查询(RT T1)、额度查询(RT T2)、优惠查询(RT T3),最终执行渠道渲染(RT T4),这种实现方式下
收银台的渲染RT = sum(T1,T2,T3,T4)
但是收银台的渲染RT必须要这么久吗?其实对于业务的分析,我们发现其实很多的服务调用无先后顺序。用户信息查询、额度查询、优惠查询这三个服务的调用其实无先后顺序,那么我们基于Tesla服务框架的异步化服务调用,见图1.6。
图1.6 异步并行模式下的收银台渲染
基于异步并行的收银台渲染方式,将并行过程中的各服务化的耗时之和变更为耗时最长的一个服务的RT。
收银台渲染RT =sum(max(T1,T2,T3),T4)
1.2.4 资金核算体系异步化
目前支付平台里,资金核算体系各个子系统:会计系统数据来源于账务系统,账务 、清算 、合规数据来源于支付核心。那么,需要在支付核心链路执行的时候同步调用账务 & 清算 & 合规,账务实时调用会计吗?其实基于对资金业务的分析,会计、清算、合规属于非强实时业务,可以通过数据变更中间件Pigeon同步数据,对这三个系统进行了解耦,如图1.7。
图1.7 资金核算体系异步化架构
清算、合规通过监听支付核心DB数据变更来获取数据,会计通过监听账务的流水库的数据变更来获取数据,从而对实时链路非强实时业务进行解耦。
1.3 热点账户问题优化
热点账户应该是每一个做支付的童鞋都会碰到的问题。美联的支付系统里,存在这各种各样的热点账户,我们将之分为三类:
1)内部户:比如渠道的待清分账号等
2)平台户:比如各种平台的营销的垫支户等
3)大商家的热点账户等。
每种热点账户的业务属性都不一样,比如商家账户,我们不能延迟记账等等。基于这些情况,我们对热点账户问题优化也基于类型:
1)内部户
针对于内部户,我们在账务中不做内部户这边的记账,而是由会计通过另外一边的账务流水去补分录。
2)平台户
针对于平台户,在账务中做了异步记账,通过定时汇总记账即可。
3)大商家
比较难的是大商家的热点问题,特别是在美联这种没有商家结算周期的情况下,每一笔的订单状态变更,都有可能涉及商家的账户资金变更。但是也有解决办法。分析其业务场景,担保入账、担保出账 、佣金扣费等占用了绝大多数的商家账户操作。针对这块我们分为两个点来做优化:
1)将商家担保账户切换到平台担保户,基于流水去统计商家担保中的金额。这种情况下,担保入账和出账的商家热点问题可以解决。
2)第一点的优化能够解决担保出入账的账务操作,但是扣费依旧会造成大量的热点账户问题,对此我们做了一个排序的任务,将扣费做到做到单商家串行 & 多商家并行。
基于上述的两个优化方案,我们解决了大商家热点账户问题。
通过对三种类型的热点账户优化进行,能够解决目前系统碰到的热点账户问题。但是各种平台户的账务流水会非常多,以担保户为例,每日的所有的出入担保户的流水,都会在这个账户之上,那么在分库分表情况下,会出现平台户所在的单表巨大无比。在这里我们引入二级子账户概念,将内部户 & 平台户在账务虚化成N个二级子账户,从而均匀的分散在各个分表里,进而解决了该问题。
1.4 账务记账事务切分
在支付核心链路里,我们对非强实时依赖的服务做了异步化的解耦,对热点账户进行了优化的处理。在账务记账的时候,我们从下面两个问题考虑优化点:
1)在账务分库分表的情况下,如何保证记账是在事务里?
2)每次记账的出账 & 入账是否可拆分?
基于这两个问题,我们对记账流程进行了事务的拆分,如图1.8所示。
图1.8 账务记账事务拆分
1)出账、入账分离。出账成功,则整体成功,入账失败可以异步补账。
2)出账 & 入账 ,每个里面都做单边账、异步记账等处理,整个支付核心链路唯一的一个事务就在于更新账务余额 & 新增流水。
目前系统中,经过这一系列的优化,单次的记账性能,基本上稳定在15ms左右。
二、稳定性提升
在第一章中,我们主要针对于支付链路的性能做了各种各样的性能提升。资金无小事,如何保证支付平台的稳定性,也是我们需要考虑的重点。我们从下面几个维度来提升稳定性。
2.1 监控先行
做稳定性之前,我们需要知道我们的系统运行情况,那么必须要做线上系统的监控,对关键指标进行管控,以支付核心链路为例,如图2.1。
图2.1 核心链路监控
如图所示,我们监控了核心链路的qps、rt、并发量等,同时也基于支付核心,我们对依赖的服务qps、rt进行监控。另外,也对依赖的DB & Cache进行监控。
通过在监控大盘中配置关键指标,能够比较清晰明了的看出目前核心链路线上运行情况。
2.2 分离核心链路
基于电商特性,我们对整个核心链路进行了剥离,如图2.2所示:
图2.2 分离核心链路
对核心链路分离的过程中,我们对链路中的各个服务中切分为核心 & 通用服务。分离的做法其实有很多,比如基于Tesla服务框架提供的服务分组功能;比如将一个服务切分为两个服务:核心链路服务和通用查询服务。
在核心链路分离之后,能够确保在任何时候,核心链路不会受到其他通用业务的影响而导致出现稳定性问题。
2.3 服务依赖梳理
目前在支付系统里,有着数十个服务,如果不对服务依赖进行梳理,系统稳定性会得不到保障。我们从下面几点来梳理服务依赖:
1)梳理平台中的强弱依赖,判定哪些是强依赖,哪些是弱依赖。
2)弱依赖做好降级和超时保护,比如收银台渲染是的白付美额度查询,这种可以埋降级开关 & 设置较短的超时时间。因为查不到额度,最多不能使用白付美支付,并不会有特别大的影响。
3) 如果是强依赖,这个不能降级,怎么办?需要对强依赖的服务提出服务的SLA治理,比如账务记账功能,我们会要求系统不能挂、rt不能超过20ms,qps需要支撑8k qps等等,基于这个约定,做子服务的优化。
2.4 降级、限流
限流是保护系统不挂的最后一道防线。
目前支付平台里面,存在基于RPC服务框架tesla的粗粒度限流,可控制在服务级别和方法级别;基于spirit的细粒度限流降级系统,我们可以在单个方法里面做限流降级功能个,如图2.3所示,我们在担保交易下单过程中,区分平台来源,做到蘑菇街担保交易流量 & 美丽说担保交易流量。
图2.3 spirit限流模式
但是不得不说,单单的qps 或者并发限流都不能完全的做好限流保护,需要两者的相结合才能达到所需的效果。
另外一点,通过对服务的依赖梳理,我们在各种弱依赖的服务中埋了一些降级开关。通过自研的降级推送平台,一旦依赖服务出现问题或者不可用,可以快速的对该服务进行降级操作。
三、压测
在对系统扩容,链路性能优化之后,怎么检测成果呢?
1)我们引入线上压测系统,通过分析业务场景,构建与线上真实场景几乎一致的测试模型。以支付链路为例,模型中以日常 & 大促的流量模型为基准,设计压测模型。需要注意的是,压测模型越与真实一致,压测的效果越好,对系统把控越准确。。
2)通过构建线上数据影子库,压测产生的测试数据,会全量写入到影子库中。通过影子库,在复用线上正式业务一致的环境、部署、机器资源下,我们能够做到压测对正常业务无侵入,对系统做准确的把脉。
3)线上业务也分为两块,一块是单机性能压测,主要是分析单机的性能水位和各项指标。另外是链路压测,主要验证系统的稳定性和服务短板。
通过压测的结果,我们能够对支付平台的性能 & 稳定性短板的分析和加以改进,能够不断的提升系统的稳定性,提升系统的容量。
四、疗效
那么,通过一系列的性能容量的提升,我们达到了什么效果?
1)平台容量方面:在16年双十一的大促压测中,我们在链路DB都扩围两组的物理的机器情况下,支付稳定在3000QPS。由于目前没有需求,我们未对DB的物理机器扩到极限,因此系统的极限性能不能完全确定,但是按照预估,理论上可支持1w QPS以上。
2)机器利用率上:相同的容量情况下,我们的应用减少为原有的1/3。
链路的性能上:如图4.1所示,以担保交易为例,交易核心的收单rt几乎在10ms,而收银台渲染在50ms,支付请求在50ms,支付回调在80ms左右。
图4.1 核心链路服务性能
同时,基于性能和稳定性的提升,我们做到了支付在历次的大促中,保持无故障的记录。
五、总结展望
在美联支付系统中,上层支付业务面向电商平台,针对电商特色做更多的业务支持。我们对平台的性能容量寻找可改进的地方,比如DB、Cache、IO、以及异步化,持续不断去优化。另外,资金无小事,如何提升支付系统的稳定性也是重点考虑的方向。