中国已成为全球移动支付第一大市场,在移动支付用户规模、交易规模和渗透率等方面大幅领先。在线买买买已成常态,特别是在 2020 年后受疫情的影响,线上经济更是发挥了重要作用,外卖叫餐、寻医问药、网购商品等都属于线上经济的范畴,在线支付是线上经济不可缺少的组成部分。
移动支付如同人们生活中的水和电一样,微信支付作为国民级支付工具,支付系统的可用性非常重要。财付通基础支付团队对系统架构不断升级演进,总结了一套保障系统高可用的方法,以解决不同阶段系统面临的可用性问题。
本文整理自财付通高级开发工程师曾明福的演讲分享,主题为“微信支付后台系统高可用保障体系演进之路”。分享主要分为三部分:一、面向 PC 支付架构;二、移动支付架构;三、思考 & 演进。
面向 PC 支付架构
基础支付平台演进历史
基础支付平台演进历史主要分为三个阶段:
移动支付 1.0 阶段及其可用性保障措施:OMP、熔断、降级、限流
移动支付 2.0 阶段及其可用性保障措施:健康度平台、公告、自动切换
移动支付 3.0 阶段及其可用性保障措施:条带化、快慢分离、Cache 化本地查询
支付系统的三个重要角色
支付系统涉及三个重要的角色:用户、商户和平台,为便于理解,我们先简单介绍一下这三个角色之间他们的一些重要的交互。在此以在线购物为例。首先,用户在商户的系统里下单,同时商户到我们的支付平台里做下单操作。下单之后会拉起收银台,平台有支付查询交互功能,展示订单、用户相关的信息。用户输入密码之后,支付完成。之后平台会给商户发通知,商户进行发货操作。
财付通基础支付平台及其发展历程
这是我们平台的全景图,最上面是微信支付和 QQ 钱包两大品牌,底层大概分为如图几大系统。上层是接入网关,负责所有业务的接入,同时会做路由的分发、过载保护机制等等。下面两层是订单和清算体系,在底层是分布式的账户系统和银行接入系统,旁边是贯穿整个交易流程的风控和反洗钱系统,为大家提供安全保障。
我们再聊一下这个平台的发展的历程。
财付通成立于 2005 年,在 2005 年到 2013 年这一阶段,主要处于 PC 时代,有一点通、快捷支付等等,这套体系的建立,为即将到来的移动支付打下了夯实的基础。
移动支付始于 2011 年,以央行发布第一批支付牌照为起点,财付通是第一批获得支付牌照的。2013 年微信支付发布了第一个版本,从此拉开了财付通在移动支付上的建设之路。实际上移动支付跟 PC 确实有很大的区别,碰到节日或者抢购的活动,流量峰值一下就过来了。我们面临的大问题,是系统要做重构、要做优化,要大大提升我们的性能。
2014 年我们重构了整个订单系统,采取了像 Cache 化、异步化等等措施。在 2015 年到 2016 年间,线下支付的场景逐步丰富,人们慢慢进入了无现金的生活阶段,用户对可用的要求变得非常高,我们提出了同城多活架构。
2016 到 2017 年业务发展量级已经非常大了,我们在安全、在灾备又做了更长远的考虑,提出两地四中心、跨城多活核架构。2017 到 2018 年,为了更好地提升用户体验,做了跨城多活条带化化的访问。2019 年之后,我们持续进行可用优化,保障整个体系在发生故障时保持有效。
架构演变之路
讲完历程,再看一下我们的架构是如何演变来支撑业务体量的。
从 2015 年开始,我们归纳为五代架构。初代架构是一个非常基础的架构,是一个集中式的系统,在这个体系下,基本上是单台的数据服务,应用是无状态的,所有的状态全部都在 DB 里面,这种体系下,没有很强的容灾诉求。
随着业务发展,我们渐渐发现这种架构有很多的弊端,往二代架构发展,将集中式的系统拆成了几大子系统,做了垂直纬度的拆分。
再到同城要做多活系统之后,就要水平拆分了,即我们的三代系统。我们在这一时期建立了分布式的账户系统,提供了分布式的能力。
在第四代系统之后有几大诉求,就是要做到支持快速的扩容,还要做一些标准化、快速的扩容和容灾等等,我们提出一个 Set 化的架构,就像集装箱单元一样,能在你需要的可用区域里面快速进行部署。
再到第五代,系统的容量已经不是核心关键的问题,可能更关注是可运维、可维护、快速伸缩等等。以下是基础支付平台可用性保障全局视图。
移动支付架构
接下来我们从刚刚讲的移动支付的三个阶段挑选一些技术来跟大家分享。首先我们看 1.0 阶段。
1.0 时代
1.0 时代我们面临的问题是什么?系统的架构还不足以支撑业务快速发展,我们想快速扩容,但是做不到。
我们的思想是先扛住再优化,措施有熔断,有降级,有限流,这些措施怎么去优化?OMP。什么叫 OMP?就是在一台机器上面完成支付所有的流程,或者支付的关键流程。因为各个服务之间穿插着调用,再加上网络的开销,是不好评估的。OMP 就相当于在最前面有个路由总线,进总线之后,路由到哪个机器,整个机器就完成支付的关键能力。如此支付尽可能减少了依赖,去除了网状的调用,极大削减网络的流量,同时,如果哪台机器出现故障可直接摘除。另外,服务的配比可以做到最优,每个单机都很好评估,很好调整,更重要的一点是有了对容量评估的基准。之后扩容时,直接用当前单机数乘一个系数即可,大大简化了流程。
熔断、降级、接口限流是经常使用的措施。熔断的主要应用场景有三个:访问非关键资源、访问具备冗余链路资源(异步)、保护下游服务(特别是无自我保护能力服务)。它有几个状态:
Closed:熔断器关闭状态,调用失败次数积累,到了阈值则启动熔断机制;
Open:熔断器打开状态,此时对下游的调用都直接返回错误;同时设计了一个时钟选项,默认达到了一定时间则进入半熔断状态;
Half-Open:半熔断状态,允许定量的服务请求,如果调用都成功(或一定比例)则认为恢复了,关闭熔断器,否则重新回到熔断器打开状态;
接口限流从部署的阶段来看有单机限流和全局限流。常见的限流算法有计数器算法、漏桶算法(leaky bucket)、令牌桶算法(token bucket)。在实现接口限流时要注意两大问题流量突发问题(临界值问题) 和流量不均匀问题。
2.0 时代
来到 2.0 的时代,线下的场景已经逐步丰富,人们已经开始步入无现金的生活,用户对线下支付是否可用更敏感了。
这个是我们 2.0 同城多活的架构。我们分层去看,第一层是接入层,是无状态的,我们直接把 CGI 接入云平台,实现自动化的运维即可。
第二层是银行接入,我们也可以做多专线银行渠道,进行健康度检测,如果 A 专线有问题,转走 B 专线。
第三层是订单,这也是最复杂的一层,因为涉及到很多资源的基层服务都在这一层。订单系统多 Set 要解决 Set 之间弱关联甚至无关联的问题。如果在 Set1 这一层有故障,用户重试的时候可以直接切换到对应的 Set 里面完成交易。
最后是账户层,通过 DB 部署实现核心账户多 Set,这个阶段我们的实现还是人工的切换。
接下来我们看一下健康度平台。左侧是实时流程,我们分为网关订单和银行接入账户系统,在这一层,各层上报自己的健康度,健康度平台采集逐层的健康度,通过健康度平台做策略分析,最终产生动作,负反馈到实时链路。这样做的好处,首先是基于主调方的健康度,能做到整个平台有一个负反馈的机制,对实时流程影响相对比较小,能做到平台化和业务解耦。
这里再看一下,多个 Set 是怎么切换的?当发现订单 Set1 这一层出现故障的时候,两个 Set 各自上报健康度,健康度平台根据阈值做流控仲裁判断,判断 Set1 出现了故障,需要做切换处理,下发路由把 Set1 屏蔽掉,把流量全部摘除,并成功切换到 Set2,这是全链路自动切换的视图。
比如,网关这一层是无状态,有问题可以直接检测健康度之后进行切换,如果接入专线有故障,可以在专线这一层屏蔽,如果是银行流水有故障,可以通过银行的多 Set 去屏蔽,通过这样的一套体系来保证全链路的多 Set 是多效的。
3.0 时代
进入 3.0 阶段,业务有了飞跃的发展,微信支付已经像人们生活中的水电一样了。我们要考虑,一些自然灾害、地震等其他情况,可能会对整个中心造成比较严重的损害。在这个时候,要怎么做才能保障我们系统的可用?
我们当时提出一个跨城的多活系统方案。跨城国标是有些要求的,要求两个城市之间的距离不能太短,但满足距离上的要求,却会给系统带来一个极大的挑战。那就是网络的延迟,以深圳到上海为例,一个 ping 包 40 毫秒,也就是说一个请求来回,什么也不做在网络上就已经可能消耗 40 毫秒了。比如深圳的中心如果真发生故障了,要往上海切,就需要考虑原来在深圳的账户数据上海是不是都已经拿到了,在深圳已经完成的交易在上海是不是都已经拿到了,没有拿到的话缺多少,怎么去解决。
当时,我们把一个城市多活的系统变成两城市的时候看到各个城市之间有大量的流量穿插,这个时候发现系统没有原来健壮了。
我们怎么去解决?第一,做条带化的访问,条带化的一个关键点就是在账户一层路由要对齐,就是把这些用户分在两城市的时候,应该要尽量做到按用户的归属层次做接入。举个例子,深圳的用户就应该从深圳接入进来,通过路由总线,在深圳的订单 Set 和深圳的账户体系去完成整个交互。要做这一层的梳理,做好账户体系和订单这一层的规划,通过最外面层的路由,把用户路由到正确的位置。
你可能会问,我原来的业务这么复杂,都能梳理清楚吗?都能满足你的要求吗?确实满足不了的时候我们怎么做?这个时候要做快慢的分离。一个用户归属在城市 2,但是又从城市 1 接入了,就要在最外面这一层,通过转发代理把它路由到对应的账户中心去完成交易。同时,这条链路是独立的,不会影响原来的快的链路,保证原来 99%以上的请求都走快链路,将慢链路的影响降到最低。
上图为读写分离,实现数据的一致访问。首先用户这一层的数据有个特点,读多写少,变更不是很频繁。这一类数据,主 DB 建在其中的一个城市,只在这里更新,通过用户的 Cache 完成城市数据的建立,通过消息的总线把所有可能变更的数据往其他中心的 Cache 里做快速准实时的数据同步,同时通过 DB 的异步复制链路,去保障其他中心 DB 数据一致,最终通过对帐体系保障各个 Cache 数据一致。通过这样的方式,即使在跨城的体系下都能访问到本地的资源,以提升性能。
思考 & 演进
前面就是通过几个阶段介绍了我们的体系,在这个演进的过程中,我们也做了很多的思考,总结如下:
系统架构不断演进:虚拟化、云化、云原生
目标始终一致:快速稳定支持业务发展
核心思想不变:腾讯海量服务之道
演进: 建立云原生下的可用性保障体系
评论