支持支付宝双11和双12的核心架构。本文转载自微信公众号“Angela的博客”,作者:Angela。转载本文请联系Angela博客公众号。依稀记得去年双11在支付宝作战室的情景。接近0点的时候,值班室里所有人的目光都盯着二级监控市场。当交易峰值曲线缓缓攀升,最后变得极其陡峭时,值班室的同学们都非常兴奋,欢呼声随着攀升曲线达到了顶峰,每秒58.3万笔交易,这同样是新的交易峰值记录,但是相比之下往年动辄翻番,涨幅在30%~40%,增速还是小很多。2010年双十一支付的峰值是每分钟2万笔,到2017年双11变成每秒25.6万笔,然后是去年的每秒58.3万笔,是首届双十一的千倍以上2009年11.为了承受这么大的支付TPS,蚂蚁做了大量的顶层架构设计和底层实现优化,其中最核心的就是LDC架构。LDC的全称:LogicDataCenter,逻辑数据中心,之所以叫LDC,是相对于传统的IDC(InternetDataCenter)提出的一个概念。IDC相信大家都很清楚,它是一个物理数据中心。说白了就是可以建网站的物理机房。LDC(LogicalDataCenter),核心架构思想是无论你的物理机房怎么部署,比如你可能有3个IDC,分别位于两个不同的城市(常说的两地三中心),它们在逻辑上是统一的。我从逻辑上看是一个整体,统一协调部署。为什么LDCLDC的出现解决了哪些问题?我们必须从架构的演变开始。上一篇文章提到的机房容灾设计的架构演进,我们用一个具体的应用来推导一次。首先看下图所示的单体应用架构。请求到网关接口,网关接口直接调用应用或服务,服务调用存储层查询或写入数据。这种架构模式最大的风险是服务和存储是单点的。访问容量和性能受限于存储和应用程序的容量和性能。在容灾方面,一旦发生故障,只能等待单点应用或存储的恢复。.后来工程师开始横向拆分应用,纵向拆分服务。水平拆分大家应该不陌生,就是增加服务器,在每台服务器上部署实例。垂直拆分是按域拆分服务。例如,一个交易系统有商户域、商品域、用户域和订单域。拆分成多个微服务,服务解耦,服务可以独立发布,应用的复杂度会更高。这种分布式架构解决了单点服务的问题。如果一台服务器宕机了,服务还是可以的,但是存储层还是单点的,而且随着业务的增长,扩容加入的机器越多,大家发现查询写入效率需要时间才能达到到某个阶段,速度变慢,分析表明存储层存在性能瓶颈。上图中只用了2台服务器连接数据库。在一个真正的分布式系统中,可能有数百甚至数千台服务器。如果都连接到一个DB,连接数、锁争用等问题都会拖慢SQL性能。知道。后来的事情大家都知道了。互联网公司开始读和写分离,把读请求和写请求分开。读写分离隐含了一个逻辑,就是数据写入后,不会立即使用。正在写入的数据和立即使用的数据之间存在时间间隔,直到从数据库同步数据后才会读取数据。实际统计表明,在常规应用中,90%的数据写入后不会立即使用。当然,我这里说的即时时间单位是ms,一般的同步延时都是几毫秒,不会超过10~20ms。但是这种架构并没有解决写的问题。随着业务量的增长,写入数据成为瓶颈。分库分表应运而生,分库分表的中间件开始流行,现在基本已经成为中大型互联网公司的标配。基本思想是按照指定的维度对数据进行拆分。更常见的是userId维度。比如取userId的后2位,可以拆分成几百个数据库和表,或者除以指定的模取余数,比如除以64得到余数即可根据余数范围0-63拆分为64个库。关于分库分表,很多人知道有垂直拆分和水平拆分两种(上面说的垂直和水平是系统的拆分,这里指的是存储),垂直拆分就是拆分根据业务维度,将相同业务类型的表放到一个库中往往是按照领域模型的概念进行拆分,比如订单库、用户库、商品库等。横向拆分是将大数据表(库)放入多个数据量较小的表(库)中,可以减轻库和表的访问压力。可以类比为系统的横向拆分和纵向拆分:横向拆分和纵向拆分系统维度加上大服务器系统按照业务领域拆分成多个子系统系统数据库维度的大数据量表为按照userId分表规则拆分成多个小表。大表根据业务领域的含义拆分成多个子表。放很多字段,如下图:垂直拆分就是从中间垂直切开,把右边蓝色的用户信息表和绿色的订单信息表拆分成两张表。库分为用户库和订单库。水平拆分就是做水平切分,减少数据量。看到这里,是不是觉得问题已经解决了呢?经过上面的分库分表,如果应用层面能搞定的话,数据库层面确实可以做到万并发的水平。但是再增加一个数量级的容量就有点困难了。为什么?因为一个库实例是所有应用共享的,即每增加一台机器,数据库连接就会相应增加,增量至少是机器设置的最小连接数。为什么应用程序需要连接到所有数据库实例?答:网关层的流量可能到任何一台服务器。比如用户A的请求到达服务器,服务器必须有用户A的userId分片的数据库连接,否则流量会被路由走,或者执行失败。分库分表只是解决了单库单表的访问压力问题,但是由于每台服务器同时连接了所有的分库实例,所以到一定阶段就没有进一步扩容了,因为有瓶颈是数据库实例的连接数。数据库瓶颈怎么办?相信聪明的已经猜到了,那就是在应用层隔离userId分片,在网关层流量路由时,将指定uid分片的流量路由到指定的应用单元执行。内部消化了这个应用单元的流量,如下图:比如uid=37487834,最后两位是34,属于00-49范围,那么用户流量直接路由到应用00-49组,所有数据交互都在本单元操作完成。这样,uid00-49分组单元中的应用只使用userId00-49分库连接的数据库,uid50-99分组单元的应用也是如此。数据库的连接数直接减半,而且还可以拆分单元,现在是2个单元,最多可以拆分100个单元。这里我强调单位这个词,因为这是LDC中的核心概念。让我重点谈谈单位这个词的具体含义。Ant中的单元有一个名字叫做Zone,Zone中部署了一个完整的服务。例如,用户可以在一个Zone中完成一套完整的业务流程,流量不需要其他Zone提供服务,有能力完成一套完整的服务。一整套服务可以在一个Zone中完成,在逻辑上是自成一体的。这样做有什么好处?如果一个Zone发生故障,路由层会直接将Zone的流量转移到其他的Zone上,其他接受该Zone流量的Zone可以分担流量和分配流量,非常方便。下图是AntZone按照region和userId分片的部署架构示意图。进行了一些简化。实际的Zone部署单元会稍微复杂一些。上面介绍的Zone能够在uid维度完成一套完整的业务流程。应用程序相互依赖的服务均由该Zone提供,服务之间的调用均在该Zone内完成。但是如果你聪明的话,你可能会想到一个问题。部分数据无法按照userid维度进行拆分。怎么可能全球只有一份呢?比如配置中心的数据是集中存储的。.其实在Ant内部,Zone分为三种:RZone、GZone、CZone。RZone:上面提到的逻辑是自包含的,是业务系统整体部署的最小单元,可以按照userId维度拆分的服务和库都部署在RZone中。GZone:GZone是一个全局区域。听名字就知道,GZone的服务和库,全球只会部署一份。一定是在某个机房,也会部署在其他地方,但是只是为了容灾,不会启用。CZone:CZone比较有意思。为什么会有CZone?它的创建是为了解决GZone的缺点。上篇《从B站崩了看互联网公司如何做好高可用》架构文章中提到,跨城调用由于距离的原因比较耗时。如果GZone在上海的服务部署,杭州机房的服务需要使用GZone部署的服务,只能跨城市、跨机房调用。很有可能一个服务有很多rpc调用,会消耗很多时间,那怎么办呢?城市之间为他们之间搭建一个数据同步的桥梁,CZone扮演着桥梁的角色,负责在城市之前同步GZone的数据,C代表城市。也正是因为我前面提到的“读写时差现象”,写入GZone的数据允许有一定的延迟,将CZone同步到其他CZone。
