中国已成为全球最大的移动支付市场,在移动支付用户规模、交易规模、普及率等方面均大幅领先。网络购物已成为常态,尤其是2020年以后,受疫情影响,网络经济发挥了重要作用。订外卖、就医、网络购物等都属于网络经济的范畴,而网络支付又是网络经济中不可或缺的一部分。
移动支付就像人们生活中的水和电一样,作为全民支付工具,支付系统的可用性对于微信支付来说至关重要。财付通基础支付团队对系统架构进行了不断的升级演进,总结出了一套保障系统高可用性的方法,以解决系统在不同阶段面临的可用性问题。
本文主要分为三部分:1.PC端支付架构;2.移动支付架构;3.思考&演进。
基于PC支付架构的支付平台演进史
基础支付平台的演进历史可以分为三个阶段:
支付系统的三大重要作用
支付系统涉及到三个重要的角色:用户、商户、平台。为了方便理解,我们先简单介绍一下这三个角色之间的一些重要交互。我们以网络购物为例,首先用户在商户的系统下单,商户在我们的支付平台下单,下单之后会拉起收银台,平台有支付查询交互功能,展示订单和用户相关信息,用户输入密码之后支付完成,之后平台会给商户发送通知,商户发货。
财付通基础支付平台及发展历史
这是我们平台的一个全景,最上面是微信支付和钱包,最下面大概分成如图所示的几大系统。最上面一层是接入网关,负责所有业务的接入,也会有路由分配、过载保护机制等。下面两层是订单和清算系统。最下面是分布式账户系统和银行接入系统,再往下就是贯穿整个交易流程的风控和反洗钱系统,为大家提供安全保障。
我们来谈谈这个平台的发展历史。
财付通成立于2005年,2005年到2013年主要处于PC时代,有一点通、快捷支付等,这个体系的建立为即将到来的移动支付打下了坚实的基础。
移动支付起步于2011年,当时央行发放了第一批支付牌照,财付通是最早拿到支付牌照的支付公司之一。2013年,微信支付发布第一个版本,为财付通打通移动支付之路打开了大门。其实移动支付和PC端有很大不同,一遇到节日或者购物活动,流量就会立刻出现峰值。我们面临的最大问题是系统需要重构和优化,才能大幅度提升我们的性能。
2014年我们对整个订单系统进行了重构,采取了可视化、异步化等措施。2015年到2016年,线下支付场景逐渐丰富,人们逐渐进入无现金生活阶段,用户对可用性的要求变得非常高。我们提出了同城多活的架构。
2016-2017年,业务发展规模非常大,我们在安全和灾备方面做了更长远的考虑,提出了两地四中心、跨城市多活核心架构。2017-2018年,为了更好地提升用户体验,我们实现了跨城市多活条带化接入。2019年以后,我们继续优化可用性,确保整个系统在发生故障的情况下仍然有效。
建筑进化之路
说完了流程,我们再来看看我们的架构是如何演进的,来支撑我们业务的规模。
从 2015 年至今,我们总结了五代架构,第一代架构是非常基础的架构,中心化体系,基本都是单机数据服务,应用是无状态的,所有状态都保存在 DB 里,这种体系对容灾的需求不是很强。
随着业务的发展,我们逐渐发现这个架构有很多弊端,所以我们走向了第二代架构,把集中式的系统拆分成几个大的子系统,做了垂直拆分。
当我们要建设同城多活系统的时候,就要进行水平拆分,这是我们的第三代系统,这期间我们建立了分布式账户体系,提供了分布式的能力。
第四代系统以后有几个比较大的诉求,就是要支持快速扩容,做一些标准化的、快速扩容和容灾等等。我们提出一个Set的架构,就像一个集装箱单元,可以快速的部署在你需要的可用区域。
到了第五代,系统的容量已经不再是核心问题,而是更加注重可操作性、可维护性、快速扩展性等。下面是总体上对基础支付平台可用性的看法。
移动支付架构
接下来我们来分享一下刚才讲到的移动支付三个阶段的一些技术,首先我们来看1.0阶段。
1.0 时代
1.0时代我们面临什么问题?系统架构不足以支撑业务的快速发展,我们想快速扩容,但是扩不出来。
我们的思路是先顶住,再进行优化。措施包括熔断、降级、限流。这些措施怎么优化呢?OMP。什么是OMP?就是在一台机器上完成所有的支付流程或者关键的支付流程。因为各个服务之间穿插调用,再加上网络开销,很难评估。OMP相当于在前端有一条路由总线,整台机器进总线之后,会根据路由到哪台机器来完成关键的支付能力。这样支付就尽可能的减少了依赖,去掉了mesh调用,也大大减少了网络流量。同时如果哪台机器坏了,可以直接移除。另外服务配比可以优化,每个单机也容易评估调整。更重要的是有容量评估的基准,后期扩容的时候,只要在现在的单机数乘以一个系数就可以了,大大简化了流程。

熔断、降级、接口限流都是常用的手段。熔断主要有三种应用场景:访问非关键资源、访问有冗余链路(异步)的资源、保护下游服务(特别是没有自我保护能力的服务)。它有几种状态:
:熔断关闭,当调用失败次数累计达到阈值时,启动熔断机制。
Open:断路器处于打开状态,此时下游所有调用都直接返回错误,同时设计了一个时钟选项,默认情况下断路器在一定时间后进入半断状态。
Half-Open:半开状态,允许一定量的服务请求。如果所有调用都成功(或一定比例),则认为恢复,熔断器关闭。否则,熔断器回到开状态。
接口限流从部署阶段可以分为单机限流和全局限流,常见的限流算法有计数器算法、漏桶算法( )、令牌桶算法( )。在实施接口限流时,主要需要关注两个问题:流量突发问题(临界值问题)和流量不均匀问题。
2.0 时代
2.0时代,线下场景逐渐丰富,人们开始走向无现金生活,用户对是否能够线下支付也变得更加敏感。
这是我们2.0的同城多活架构,我们分层来看,第一层是接入层,它是无状态的,我们直接用CGI跟云平台对接,实现自动化运维。
第二层是银行接入,我们也可以设置多个银行专线通道,做健康检查,如果专线A有问题,就切换到专线B。
第三层是订单,也是最复杂的一层,因为涉及到很多资源的基础服务。订单系统有多个Set,需要解决Set之间关联性弱甚至无关联性的问题。如果Set1层出现故障,用户重试时可以直接切换到对应的Set完成交易。
最后一层是账户层,通过DB部署实现多套核心账户,现阶段我们的实现还是手动切换。
接下来我们看一下健康平台,左边是实时流程,分为网关订单和银行接入账户体系,在这一层,每一层都会上报自己的健康情况。健康平台会把每一层的健康状况收集起来,通过健康平台进行策略分析,最后生成动作,并负反馈给实时链路。这样做的好处是,首先基于主调用方的健康状况,整个平台可以有一个负反馈的机制,对实时流程的影响比较小,可以实现平台化和业务解耦。
我们先看多个Set是如何切换的,当发现顺序Set1层出现故障时,两个Set上报健康状态,健康状态平台根据阈值做流控仲裁判断,判定Set1出现故障,需要切换,路由下发,阻断Set1,移除所有流量,成功切换到Set2。这是全链路自动切换的一个视图。
比如网关层是无状态的,如果出现问题,可以直接检测健康状态然后进行切换;如果接入专线出现故障,可以在专线层进行阻断;如果银行流量出现故障,可以通过银行的多路复用进行阻断;这样的系统可以保证整个链路的多路复用是有效的。
3.0 时代
进入3.0阶段,业务突飞猛进,微信支付已经成为人们生活中的水电一样的存在。我们要考虑到一些自然灾害,地震等情况,可能会对整个中心造成严重的破坏。这时候,我们该怎么做才能保证我们系统的可用性呢?
我们提出了跨城市多活的系统解决方案。跨城市的国标有一些要求,要求两个城市之间的距离不能太短,但是满足距离要求会给系统带来很大的挑战。那就是网络延迟。以深圳到上海为例,ping一个包是40毫秒,也就是说一个来回的请求可能在网络上消耗了40毫秒而什么也没做。比如说如果深圳的中心真的出现故障,需要切换到上海,那么就要考虑深圳原来账户的数据在上海是否已经拿到了,在深圳已经完成的交易在上海是否已经拿到了,如果没有,那么遗漏了多少,如何解决。
当时我们把一个城市的多活系统改成两个城市的的时候,看到城市之间穿插了大量的流量,这时候我们发现系统没有以前那么健壮了。
那怎么解决这个问题呢?首先要实现条带化接入。条带化的一个关键点就是在账号层面把路由对齐。也就是当这些用户被分到两个城市的时候,我们要尽量按照用户的归属层级来做接入。比如深圳的用户,应该从深圳接入,通过路由总线、深圳的订单集、深圳的账号体系完成整个交互。我们需要梳理好这一层,做好账号体系和订单层的规划,通过最外层的路由把用户路由到正确的位置。
你可能会问,我原来的业务那么复杂,我能梳理清楚吗?能满足你的要求吗?实在满足不了你的要求怎么办?这时候就需要把快慢链路分开了。一个用户属于城市2,但是从城市1访问,最外层要通过转发代理路由到对应的账户中心才能完成交易。同时这条链路是独立的,不会影响原来的快速链路,保证原来的99%以上的请求走快速链路,把慢链路的影响降到最低。
上图展示了通过读写分离实现数据的一致性访问。首先用户层的数据有一个特点就是读多写少,变化不是很频繁。对于这类数据,会在其中一个城市建立主DB,只在这里更新。用户完成城市数据建立后,通过消息总线将所有可能变化的数据快速同步到其他中心。同时通过DB的异步复制链路,保证其他中心DB数据的一致性。最后通过对账系统保证各个数据的一致性。这样即使在跨城市系统也可以访问本地资源,提高性能。
思考与进化
上一节通过几个阶段介绍了我们的系统,在这个演进过程中,我们也做了很多思考,总结起来有以下几点:
- END -
往期回顾
技术交流,请加微信: jiagou6688 ,备注:Java,拉你进架构群