对于支付宝、微信支付等国民应用来说,海量交易带来的系统可用性问题已经成为关系国计民生的问题。本文总结了微信支付核心订单系统的架构实现,以及海量交易带来的扩容、成本、容灾和灰度问题及解决方案。最终通过系统架构的多次迭代,建立了基于Mysql的单机存储引擎。与存储强耦合的高可用分布式订单系统。本文主要介绍一个基于条带的高可用分布式订单存储系统。条带是由无状态服务和有状态存储服务组成的条带架构的基本单元。通过条纹可以实现线性缩放的能力;下单时,跳单操作可以让一个订单重试来替换可用的条带,可以处理少数条带不可用导致的订单不可用问题;同时,基于条带的架构还带来了冷热分离、故障压缩、差异化服务、热点均衡和灰度控制等能力。虽然基于条带的架构带来了诸多优势,但也造成了业务与存储的强耦合。另外,业务开发人员也需要明白,整体架构在开发的时候不能更多的关注业务逻辑。一、引言随着移动支付的快速发展,移动支付用户数量不断增加,移动支付已经悄然融入人们的生活并发挥着重要作用。在支付系统中,一笔交易往往需要多个相关系统的配合,包括支付产品系统、订单交易系统、风控系统、支付系统、账户系统、商户系统、账户系统、清算结算系统等。交易系统,一笔交易由一个订单标识,订单系统需要提供创建订单、支付订单、查询订单、关闭订单和订单退款的能力。订单系统是其他系统的依赖系统,其可用性将直接影响整个交易系统的可用性。交易系统的易用性将直接影响用户的交易体验和整个品牌的美誉度。传统银行基于大型商业服务器和许可的数据库软件构建自己的交易系统。互联网与传统银行的不同之处在于,它们往往使用小型廉价的商业服务器和开源数据库软件来构建自己的交易系统。此外,传统银行的交易系统是中心化的,而互联网企业往往采用分布式系统自建系统,这对数据的一致性、容灾、可用性提出了更高的要求。对于大型企业或者第三方数据库公司,他们会开发一些自己的分布式数据库存储,比如OceanBase、TiDB等,但是很多公司还是会使用开源的mysql作为他们的数据库系统。基于mysql的易扩展、高可用、支持海量存储的订单交易系统,对于企业来说也是一个很好的解决方案。本文将讨论一个基于mysql的海量订单交易系统,高可用和易扩展是整个系统的两大特点。为了实现整个系统的高可用,可用性主要包括三个方面的改进:使用HaProxy进行数据库的快速切换,解决存储不可用问题。通过条带化进行物理隔离可防止单个存储故障导致的不可用性扩散。通过跳过系统顶部的订单减少了逻辑服务和存储不可用的影响。为了解决系统的容量,整个系统的容量主要通过条带单元的水平扩展来扩展,条带结构可以很好的解决冷热数据分离的问题。在系统的垂直方向上,整个系统主要分为代理层、逻辑服务层和存储层;在水平方向上,系统由许多物理上相互隔离的条带组成,一个条带包含相应的逻辑服务和存储,条带也是水平扩展的基本单元。本文主要是先描述整个系统的总体架构,然后描述传统架构中存在的问题并提出相应的解决方案,然后讨论整个架构的实现细节以实现可用性和易扩展性,讨论整个系统的快速发展通过组合通用组件。2、业界目前交易系统的可用性主要分为无状态服务的可用性和有状态存储的可用性。无状态服务的可用性更容易解决,而有状态存储服务的可用性成为整个交易系统的核心瓶颈。为了解决有状态存储服务的可用性,业界也开发了很多金融级的分布式系统存储方案。例如,Google的Bigtable、MegaStore和Spanner;Facebook的MyRocks;阿里的OceanBase和XEngine;腾讯的TDSQL;PingCap的TiDB。这里的存储主要分为两大方向:基于关系数据库构建的分布式关系存储系统和基于NoSql的分布式存储系统。OceanBase、MyRocks、TDSQL等分布式关系存储系统;Spanner、X-Engine、TiDB等分布式NoSql存储系统。在现代互联网时代,谷歌的存储技术是整个互联网行业的技术标杆。其发表的GFS、Bigtable、Spanner等技术成果确立了近年来存储发展的方向。其存储系统也经历了从Bigtable、MegaStore到Spanner的演进,而Spanner是第一个将数据全局分布并支持外部一致性的分布式事务的系统。无论是存储的理论研究还是技术实现,谷歌都是这个时代的先行者。作为技术实力与Facebook同样强大的互联网厂商,MyRocks是Facebook开发的基于RocksDB的开源MySQL存储引擎,一直稳定支撑着Facebook的海量业务,是Facebookmysql的主要分支。阿里作为中国电商的代表企业,每天都面临着海量的交易。海量交易虽然代表着业务的快速增长,但也对整个交易系统的易用性、可扩展性、一致性和性能提出了更高的要求。在中国移动支付和阿里双11整体高速增长的带动下,阿里的交易系统也在交易海啸中快速成长。整个阿里集团不仅完成了IOE的去除,也完成了存储的自研,打磨成为业界最顶尖的互联网分布式金融存储产品。阿里巴巴目前的分布式存储产品包括自研的金融级分布式关系型数据库OceanBase,以及阿里巴巴数据库产品事业部自研的OLTP数据库存储引擎X-Engine。OceanBase作为完全自主研发的金融级分布式关系型数据库,具有强一致性、高可用、高扩展性、高性能、高兼容性、低成本等特点。OceanBase是一个基于单机关系型数据库的类Bigtable分布式存储系统,根据数据特性分为基线数据和更新数据;X-Engine的定位是为阿里云Serve上的公有云客户提供低成本、高性能的数据库。X-Engine采用基于LSMTree的分布式架构,通过优化和硬件加速,以更低的成本提供高性能读写的OLTP存储解决方案。伴随着微信支付的快速发展,以及用户的不断增长和交易量的增长。腾讯财付通作为底层支付服务商,拥有自研的金融级分布式数据库TDSQL,不仅支持微信红包业务,还在腾讯云上为更多企业用户提供分布式数据库解决方案。由于历史原因,微信支付的核心订单系统并没有将所有的可用性都转移到分布式存储系统中,而是基于业务与存储强耦合的单机关系型数据库开发了高可用的订单系统解决方案。上述业务与存储强耦合的订单存储方案,也是本文讨论的方案。虽然没有采用一些分布式存储方案,但可能更适合中小型互联网企业搭建独立的高可用订单存储系统。除了阿里和腾讯之外,PingCap是一家专注于开源的新型分布式数据库公司。其开发的分布式关系型数据库TiDB项目,具有分布式强一致性事务、在线弹性水平扩展、故障自愈高可用、跨数据中心Multi-active等核心特性,为HTAP提供一站式解决方案.TiDB虽然交易量不多,但作为一家专注于自研存储的公司,它代表了中国自研存储的努力与崛起。3.系统架构根据上一节的描述,订单交易系统的可用性更侧重于有状态存储服务的可用性,一些高可用强一致性的分布式存储方案可以解决这个问题。前面提到,微信支付的核心订单交易系统并没有采用高可用、强一致的分布式存储系统,而是开发了基于单机存储、存储与业务强耦合的订单可用性解决方案。这里的解决方案也可以为更多的中小企业提供自主搭建可用订单系统的解决方案。图1:订单系统架构概览图1显示了整个系统的简要结构。整个系统由一个代理层和若干个条带组成,每个条带包含无状态逻辑服务和有状态存储。.整个系统纵向分为三层:代理层、逻辑服务层和存储层。其中,代理层的主要功能包括订单路由和跳单、逻辑服务层聚合业务特性、数据增删改查、单机交易等,存储层负责数据存储;在水平方向上,它是由多个可动态伸缩的条带组成。条纹是系统的基本单位。通过条带逻辑聚合,实现读写分离、冷热分离、差异化服务,提升版本发布质量。整个系统的容量通过动态增减条带实现动态扩容和缩容;系统可用性通过针对存储不可用问题提出针对性的解决方案和优化,提高整个系统的可用性。系统中的每个条带都是物理隔离的。如果存在不可用的订单,代理层可以通过跳过不可用的条带来确保订单创建和订单支付的高可用性。订单不可用仍会影响条带内的订单查询和订单退款。在实践中,订单查询和订单退款可以比订单创建和订单支付更灵活和更好的容忍度。通过以上描述,整个系统通过无状态代理层和跳单保证了系统创建订单和支付订单的高可用。条带内的无状态逻辑服务部署在三台机器上,所以一个条带内的所有逻辑服务同时不可用的概率会极低;条带内存储也部署在三台机器上,一主两备可以保证集群的数据容灾和可用性,集群内主备之间采用半同步,保证数据的最终一致性(可以使用基于Paxos转换binlog的强一致性数据存储,如PhxSql)。订单号基于业务与单机存储强耦合的订单存储方案。其实质就是将存储层的分布式方案上移到业务层去实现。对于一般分布式存储系统中主键的概念,在分布式订单存储系统中自然可以用订单号代替。存储的分布一般采用基于Range或Hash的分片方案。一般先生成一个全局唯一的主键,然后根据主键确定数组的分片。我们先称之为分片绑定。文中提出的方案是随机选择其中一个可用分片作为当前订单号所在的分片,然后在订单号中记录该分片的编号并创建订单。我们称这种方案为分片的后期绑定。Ordernumber=(versionnumber,stripenumber,time,ordernumber)订单号主要由版本号,stripe号,时间信息和订单号组成。其中,版本号用于控制订单号的版本升级;stripenumber存储数据所在的shard,根据stripenumber进行路由;时间信息用于记录订单号的生成时间,判断数据的冷度、热度和温度;订单号用户保证订单号全球唯一。按照我们的stripescheme,可以降级为(stripnumber,timeinformation,ordernumber)unique,这样订单号只需要在一个stripeband内唯一。同时会降低对全局唯一序列号生成器的依赖,使得每个条带都可以使用条带内的序列号生成器,进一步提高整个系统的可用性。路由信息表路由信息表维护着每个条带的路由信息??。每条路由信息维护每条条带的编号,逻辑服务的地址和端口,存储服务的地址和端口,条带是否可用,条带是否可用。系统的冷、热和暖条件,以及它所属的区域。如表1所示,条带编号为递增的ID,无需添加新条带,自动为条带分配新的ID;分区是条带的逻辑聚合概念,我们可以基于聚合分区构建Key商户分区、普通商户分区、预发布分区、冷分区提供差异化??服务、冷热隔离等能力。每个条带都有自己对应的逻辑服务和存储服务。我们可以通过配置的地址在逻辑上形成一个逻辑隔离的条带。如果机器没有混合部署和重复使用,条带也是物理隔离的。.availablestatus表示当前stripe是否可用;冷热状态表示DB中数据的时间特征,我们大致分为冷热暖三类。代理服务作为整个订单系统的入口,代理服务需要提供下单、支付、查单、清单等接口。下单是创建订单,支付和关闭订单是更新订单,查看订单是查询订单。下单时,代理服务需要正确、均匀地选择条带,并在部分条带不可用时跳单,以确保在有限的跳过次数内找到可用的条带。支付、查单、清关,需要正确解析订单号中的条带信息,进行正确的路由。由于代理服务是一个无状态的逻辑服务,为了提高代理服务的可用性,可以通过水平部署多个代理服务实例来解决。假设只有有限数量的代理服务实例同时不可用,业务方可以在一次请求重试失败后将请求路由到其他正常的代理服务,从而保证代理服务的高可用。为了扩展系统的容量,传统的基于Mysql的系统架构一般采用水平分库分表的策略。通过对主键进行哈希处理,将数据分布在不同的机器上,以增加系统的容量。比如实际系统假设有8组DB,主键可以存储为8的余数,但是这种方案有两个缺点:冷热分离和双重扩容。在订单系统中,订单记录很少在一段时间后进行订单查询和订单退款,因此具有明显的冷热特性。为了更好地利用机器资源,一般将x冷数据分离存放在低成本的机器上进行存储和访问。对于上面的Sharding方式,我们需要将冷数据按日表进行分离。对于上面的Sharding方式,在扩容的时候会选择增加DB的数量到16组。需要将扩展??后的数据复制到新机器上,然后根据16个请求重新计算路由。上述过程称为翻转。双重扩张。上述容量的翻倍对于实时订单系统来说是无法承受的。我们更愿意在不影响已经生成的订单的情况下线性扩展和收缩系统的容量。为了更好地支持冷热数据分离和线性扩展,我们提出了基于条带的动态扩展架构。条带是存储的基本单位,包括无状态逻辑服务和有状态存储,可以通过增加或减少条带数量进行线性扩展。在事务系统的很多场景中,事务会需要操作多个资源同时成功或失败,比如转账,同时反转多个文档状态等。在单机关系型数据中,我们会使用单机事务解决它们。同样对于分布式系统,系统需要具备分布式事务的能力。由于分布式事务实现复杂、性能低下,在业务系统中,往往将分布式事务转化为独立的事务进行解析,或者根据核心程度将分布式事务分为初级事务和次级事务。通过异步组件进行异步补偿,完成整个事务。另外,由于交易系统中的一个交易往往会操作多个相关的交易文档,我们可以将多个相关的文档部署在同一个分片中,这样就可以将它们转化为独立的交易进行解析。通过以上分析,我们将系统事务转化为条带内的单机事务和跨条带的异常补偿事务,使各个条带充分解耦,实现物理和逻辑隔离。在跳单之前,系统中有一个条带健康检查服务,实时检测和收集条带的健康度和时间消耗。此外,在某些情况下,需要手动屏蔽不可用或可用的条带(例如增加或减少跳转顺序,冷热分离等)。下单时,代理服务结合条带健康度、黑名单等信息,根据每个条带在短时间内的请求量,从可用条带中选择一个可用条带,然后根据订单号。随着生成订单。第一次成功,直接返回订单号;如果不是,此时可以阻塞当前条带,并在剩余的可用条带中进一步选择一个可用条带,直到重试次数达到上限。我们将上述不断重试寻找可用条带的过程称为跳序。跳单的主要目的是通过有限的重试次数,跳过不可用的条带,保证下单操作的高可用。HealthCheckService条带健康检查服务是所有条带的观察者。它通过定期模拟真实交易来检测每个条带的可用性和耗时情况。根据健康检查服务提供的stripe可用性和耗时信息,可以在下单时以更高的概率选择可用的stripe,有效阻断不可用的stripe。strip是否可用还需要提供良好的评估策略和bottom-up的方案,防止网络持续抖动??导致over-detection和所有strip不可用。4.订单流程对于订单系统来说,作为支付系统的核心流程,往往需要提供创建、更新和查询订单的能力。对于订单的复杂查询,为了不影响实时交易环节的可用性,备机的数据会通过可靠的异步组件同步到非实时数据库,进行复杂查询或统计操作。下面将介绍基于上述条带化架构创建订单、修改订单、查询订单的过程:创建订单的过程如表2所示,入口的路由服务主要完成生成条带不可用时的订单号和跳转。单一操作。这样可以保证订单创建的高可用性,即使有几个不可用的条带,整个系统仍然可以下单。订单更新流程如表3所示,业务方在下单过程中获取订单号后,业务方携带订单号,代理服务解析订单号中的带号,确保请求是在相应的乐队中制作的。并正确找到对应的DB信息。查询订单对于订单查询,我们可以将查询分为实时读请求和非实时读请求。实时读请求读取主库数据,主要为核心环节提供精准数据查询;非实时读请求读取备库的数据,主要提供核心链路降级备读和非实时链路读。如表4所示流程,业务方在下单流程中获取订单号后,业务方携带订单号,代理服务解析订单号中的条带号,可以保证请求在相应的条纹中制作并正确处理。找到DB对应的信息。5.架构特点线性扩展对于具有海量事务的系统,线性扩展成为一个重要的特性。线性扩展为整个系统应对特定时期的交易高峰提供了更大的灵活性,可以通过简单的扩展和收缩实现交易处理能力和成本的平衡。对于业务可能持续快速增长的系统,线性扩展能力可以应对不必要的系统重新设计和重构。故障压缩由于每个条带在逻辑上和物理上都是隔离的,无论是条带内DB引起的故障还是灰度发布引起的故障,对应的故障只会被压缩在条带内,不会波及到整个系统失败。雪崩。通过统计,我们可以简单地估计出每个订单不可用的概率,进而估计出整个系统不可用的概率。差异化服务根据我们抽象的条带概念,我们可以将一些条带聚合成一个分区,某些商户的请求只能落在某些分区的条带中。这样,不同的分区提供不同的机器、带宽等,可以实现对重点商户和非重点商户的差异化服务。冷热分离当系统中某些条带的容量达到了警告值,或者其中的数据已经超过了一定的冷却阈值。我们可以让stripe只读可更新,但是不能再写数据。当数据访问量下降到一定阈值后,可以停止写条带内的所有数据,复制到冷存储中,然后将条带路由信息中的存储服务地址修改为所在新机器的地址。冷数据位于。然后把旧机器上的数据删掉,加上一个空的stripe,这样就可以轻松完成冷热数据的分离,上面的过程可以完全自动化。灰度控制在互联网系统的可用性问题中,统计表明很多版本问题可以通过合理的灰度来及早发现和解决。基于条带的架构可以轻松构建预发布环境。预发布环境通过后,可以控制新版本先灰度发布部分生产条带,然后逐步灰度到所有条带。同时,可以通过控制某些条带的请求量来实现更细粒度的灰度。在选择分区进行热点平衡时,可以统计每个条带最近创建的订单数,进行合理的条带选择,从而达到最大的数据平衡,避免传统分片模式下数据倾斜的问题。6.备份、容灾和恢复备份为应对机架级不可用、机房级不可用、城市级不可用,需要通过数据备份进行容灾。可以根据业务的容灾情况选择合理的容灾级别。通常,业务会选择一主两备的三机备份策略。数据一致性如果在stripe中使用Mysql作为存储引擎,Mys??ql支持同步复制、异步复制、半同步复制、增强型半同步复制和MGR(MySQLGroupReplication)。通常,我们很少使用同步和异步复制。在Mysql5.7增强半同步之前,DBA们都会用到半同步复制。但是,如果主机宕机,切换到备份,可能会出现某些数据不一致的情况。为了解决半同步带来的问题,Mysql5.7之后引入了增强的半同步。但是MGR是一种基于Paxos的强一致性复制方案,在MGR行业很少有互联网公司采用。对于容灾,我们假设所有的机房都在一个城市的不同机房。为了应对同城机房级别的不可用,我们需要将三个数据分布在同城三个不同的机房,同时保证每个机房拥有相同数量的主机和备用机,以及机房级别的负载均衡。当机房级及以下出现不可用时,可快速切换主机,保证业务的可用性。如果整个机房不可用,最多会损失1/3的交易量。但是对于条带架构,我们可以快速调整条带路由信息表,将不可用的条带屏蔽掉,这样只会有很短的时间不可用。7.架构上的不足和改进对分布式事务不是很友好。事实上,更多的能力可以归结为解决方案的存储,这对业务人员的架构能力提出了更高的要求。如果改造现有系统的成本太高。8.总结以上首先介绍了基于单机Mysql的业务与存储强耦合的高可用海量分布式订单系统。基于抽象的条带概念,整个系统架构自然具有一定的线性扩展、故障压缩、冷热分离。、灰度控制、差异化服务、热点均衡能力。虽然不同于支付宝使用强一致性分布式存储系统来保证分布式存储服务的高可用,但这种建立在单机Mysql之上的架构更适合没有自主研发能力的中小企业。分布式存储的发展。从目前业界的存储演进方向来看,强一致性的分布式关系型数据存储系统仍然是业界努力的方向。
