前言:从网上找的首届阿里中间件技术峰会上的一个报告,2017年7月的,报告的名字叫阿里电商架构演变之路,感觉不错所以看了一遍,在此记录一下,复制了其中大部分内容,并进行了整理,然后在晦涩之处用自己的语言解释了一下,用于个人复习。
参考:
https://yq.aliyun.com/articles/147755
https://developer.aliyun.com/article/161190
目录
第一章 淘宝1.0
整个淘宝网从开始想去创建,到真正上线,总共经历了一个多月的时间。那这一个多月的时间都做了些什么呢?
第一件事情,我们开始做技术选型,决定我们后续怎么发展;第二件事情,如何在一个多月的时间,让我们的网站上线。
我们购买了一套基于LAMP架构的电商网站,并且拿到源代码,我们对其进行二次开发,比如界面的UI改动,上下title的改动,其中最大的改动就是我们对它的数据库做了读写分离。
第二章 淘宝2.0
2.1 1.0架构出现的问题
随着业务量的增长,就会发现一些瓶颈,主要来自于数据库。当时的数据库是MySQL4,还不够稳定,数据库经常会出现死机。
因此,我们直接把数据库换成oracle,通过PHP和oracle直接去连接进行操作,但PHP不支持连接池,即使使用一些开源的PHP中间件,让PHP去连接oracle,还是非常不稳定,连接池的中间件经常卡死。
2.2 2.0架构
我们开始考虑将技术体系转成Java,因为Java在企业级的应用中,有着比较成熟的生态。转化的过程中也还是很坎坷的:第一,我们是一个线上正在运行的系统;第二,系统当时正在大规模的增长。所以说把系统替换成Java,最好的方法就是分块替换。同时发现,oracle的写入量还是比较大的,当时还做了一个search,把产品搜索和店铺搜索放到search里面,这样每一次的请求都打到数据库里面了,这样我们就完成了1.0架构到2.0架构的演进。
第三章 淘宝3.0
3.1 2.0架构遇到的问题
3.2 2.0到3.0过程中的架构
所以我们开始对架构升级。第一,我们增加了内存cache,cache主要是解决数据库压力过大的问题,我们自己研制了一套Key/Value 分布式缓存(TAIR),就是在数据库前端加了一个内存cache,缓解了我们数据库的压力。第二,我们增加了分布式文件系统(TFS),之前的文件系统在商用的时候,成本太高,服务器的量非常大,所以我们研发了自己的一套文件系统。
3.3 2.0到3.0过程中的架构遇到的问题
- 技术团队规模500人左右,维护变得越来越复杂
- 单一War应用,应用包一直增长,更新业务特性越来越慢;数据逐步形成多个孤岛,无法拉通
- 基于传统应用开发架构,业务爆发,弹性不足,单点故障影响巨大
- 还有性能问题。随着前端业务量的增大,服务器逐渐增多的时候,oracle也出现了连接数的瓶颈。所以我们必须开始做新的架构,让整个架构往前走一步。
3.4 3.0架构
我们迈向了3.0架构。系统进行拆分变小,拆分系统主要是把系统分层。把系统分成三类:
第一类是c类,是中心类,比如说会员、商品、店铺等等,基于这些中心上面开发各自的系统。比如说商品详情、交易下单;
还有一些公共的类,是p类,比如交易平台,这是从业务上进行拆分。几个比较知名的项目,比如千岛湖项目(拆分出交易中心、类目属性中心)、五彩石项目(拆分出店铺中心、商品中心、评价中心)。
还有一类是垂直团队类。
伴随着技术架构的改动,我们的业务结构也开始进行改动,开始成立了相应的团队。上图的下半部分就介绍了我们架构的演变过程。开始时,是all in one,1~10在维护一个项目。第二个阶段是10~1000人维护的MVC架构,实现了前后端分离,各司其职。第三个阶段是RPC,就是把各个系统进行拆分,然后各个系统之间进行通信。第四个阶段就是SOA这样一个模式。
这里关于上面所说的分类自己又思考了一下,感觉上面描述的并不是很清楚,感觉应该是下面的意思,不保证对哈:
C类就是专注于提供一个服务,如会员服务、商品服务、店铺服务。
P类是提供公共服务的一些类,如支付类,不同的业务(淘宝、飞猪)都需要通过此类向银行扣钱。
垂直团队类提供一些合成服务,如有一个读取商品信息接口,此接口需要调用C类中的商品服务、店铺服务,垂直团队实现此接口。
3.4.1 RPC框架
我们开发了轻量级的HSF框架,它是基于Java interface 的RPC框架,使得开发系统时就像开发本地应用一样去正常的调用Java。使用这个框架可以真正远程的调用到其他的系统上面。
一般RPC都带着服务发现,服务发现怎么办呢?
一个应用A如何知道应用B里面有多少台机器呢,你的ip又是什么?最简单的方式就是静态列表,记录下ip,做轮询策略,先调用A的1号机,再调用2号机。这样就没法实现一个动态的发现。所以在这个过程中,我们有一个动态的配置中心(configserver),在你服务上线的时候,作为provider把服务放到configserver上去,当需要消费这个服务的时候,会看哪些服务可以调用,然后把这个列表拿到。Configserver会自动把相应的provider的ip推送到consumer上面。然后consumer会自动发现provider的服务,然后彼此会发生一个相互调用关系。如果configserver挂掉之后,你的provider是挂不上去的,但是已经发上去的服务是不受影响的,因为configserver已经把相应的服务推送到consumer上面。当我们把分布式系统变得庞大之后,其实各个系统各司己职就好了。
3.4.2 数据库拆分
Oracle其实也产生了性能瓶颈,而MySQL经过了多年发展,已经非常的成熟和稳定了。我们考虑把数据库做拆分,也就是去IOE。对MySQL进行拆分,其实就是按照一定的规则去分库分表。拆分首先就是读写分离,然后做垂直拆分,还有水平拆分。垂直拆分主要是按业务来拆分,当垂直拆分到一定程度之后,有一些大业务还是不能承担这样的数据量,我们只能水平做分库分表,做sharding的拆分。分库分表就基于某一些主键算,如果主键符合什么样的条件,就Sharding到什么服务器上面。但是让每一个业务系统去做的成本是非常高的,一定要有一个中间通用的东西,能够解决数据库水平拆分的问题。
所以我们开发了一套数据库的中间件叫TDDL。TDDL就是在中间件层面支持数据库的水平拆分,业务就是在写单库一样,你不需要感知太多的东西,但是我已经把数据分散到各个数据库里面去了。当时还有一个系统是CORONA,CORONA今天我们已经把他放到云上面去了,它遵循标标准的JDBC协议,应用在写代码的时候还是遵循标准的JDBC协议,完全不需要感知任何的东西,用的也是标准的JDBC包。把请求送到我们的server上面,server去做Sharding处理,整个对应用是完全没有感知的。
3.4.3 MQ集群
例如,我要创建一个订单,订单后面依赖了200多个系统,如果按照同步调用一步步进行下去,可能最终返回的返回时间会非常长,这时候怎么办呢?我们会选择并发,A去调用B、去调用C、去调用D的这种HSF直接调用。但这时存在一个问题,如果说下游依赖的200多个系统中有一个系统被挂起了,就使整个请求被挂起了,然后接下来就很难进行了,而且这时如果对方的系统出现了严重的问题,会使我后续的请求都被挂起,最终也会把我的系统拖垮。这个时候我们需要一个异步解耦的方式,那么就产生了消息中间件。消息中间件就是当A要去调用的时候,然后就会发一个消息,然后下游的系统开始订阅这条消息,各自去处理各自的,处理完之后把结果返回给中间件,这样就完成了异步通信过程。那么如果其中某一个系统发生了问题,前端的交易系统创建订单的时候,它只要把消息发出去就不用管了,等所有的事情都处理完再回调它就可以了,就不会关注你如何调用。
3.4.4 分布式追踪
随着我们整个分布式架构的演进,架构变得异常复杂,依赖关系也变得异常复杂。这时候我们就想能不能可视化线上的问题,方便我们知道究竟发生了什么、它们之间的调用关系和调用链路是什么样。于是乎就产生了分布式追踪(EAGLEEYE)。有了EAGLEEYE,我们就能清楚地知道一个请求过来,是怎么样从入口一直传递到最后,中间都经历了什么,然后哪一块可能是有问题的。像图中这样报错位置会标红,我们就可以清晰的知道是哪个系统出的问题。我们不需要再像以前一样,大家各在排查自己的系统,导致我们处理问题的时间比较长。
3.4.5 其它系统
愚公:有了分库分表,我们如何把oracle的数据迁移到MySQL?对此,我们开发了几个中间件,第一个就是“愚公”,把oracle里面的数据通过“愚公”一点一点地迁移到MySQL里面去,放到各个库里面,同时保证我们的业务不受影响。
精卫:当我们把数据库做分库分表之后,我们还需要在数据库和缓存之间做一些trigger,当数据变了,需要触发一个事件,可能以前我们需要通过写一个程序来实现,现在我们也沉淀了一套中间件系统——精卫,它会监听每个数据库的变化,当数据库每个记录发生变化之后,它就触发一个事件,接听到这个事件之后,业务方可以根据自己的业务需求写一个精卫的worker,然后放到精卫里面去,触发相应的逻辑。最典型的就是触发cache逻辑。随着我们IDC架构之后,当我们的数据在单点写完之后,其他的地域如何感知到数据的变化呢?就是通过精卫这样一个系统实现的。当数据库变化了,精卫会触发失效cache,当业务请求再过来的时候,就会把cache里面的数据填充成最新的数据,然后能够让业务看到最新的数据,就不会出现当A单元数据变动了,然后B单元和C单元的cache没有生效的情况。
第四章 淘宝4.0
4.1 3.0架构遇到的问题
资源中最重要的问题就是资源受限,当我们的机房都在一个地方,这个地方并不能无限扩展,随着我们服务器数量越来越多,那么这个地方可能就放不下我们的服务器。比如2013年我们买到机器之后,杭州的机房没有地方去放。随着我们搞双十一活动,伴随着销售额和秒级峰值都有很大的提升,我们的成本也会有一定的提升,我们最终也会遇到单地域资源的限制;第二个是扩展性,有些业务可能不能只在这一个地方部署,因为别人访问我会比较慢,需要部署到国外,这时候业务有一个异地部署的需求;第三个就是一个容灾的需求,毕竟天灾人祸都在所难免。比如说同样是在2013年,杭州是40度的高温,我们的机房差点被限电,还好最终没有限。但是这也给了我们一个警示,就是我们必须要对我们的架构进行演进。如果不演进的话,总有一天我们的资源会不够。
4.2 4.0结构
架构演进就是不把鸡蛋放到同一个篮子里面,我们开始把我们的业务划分出各个逻辑的单元,可以把它们放到各个地方,然后让我们整个系统分散到全球,各个系统之间也没有过强的依赖,当某一个地域出现问题之后,不会影响到其他地方,我们只需要把流量切换一下就可以。现在我们应用的就是这套架构。
们按照业务的维度,把业务划分成各个逻辑单元。比如说第一个要做单元化的是交易单元,我们就把整个交易链路划分出来,放到各个逻辑单元里面,然后在水平方向上进行拆分,然后把数据再在水平上做一个区分。单元内的数据就不要发跨单元。如果跨单元就会出现一些问题,比如说容灾问题,如果A挂掉之后,可能不止影响到A,其他单元也会受到影响。如果发生跨单元调用,延时也会比较长,对于最终用户下单的体验也是非常差的。所以我们要遵循单元封闭的逻辑,让每一个单元内的调用关系都封闭在自己的单元内,不要发生跨单元。
在技术架构上,我们对技术做了一个分层,并且定了几个原则,除了单元封闭原则之外,还有全局路由,全局路由解决的是全局用户流量的分配,当一个用户流量进来之后,它会按照我们的路由规则分配到相应的单元里面去。当用户流量进来,会跳到CDN,CDN知道其属于哪个单元。然后到了某一单元之后,接入层会判断其是否属于这个单元,如果不属于,会让其跳到正确的单元里面去。如果属于这个单元就继续往下走,直到走到数据库这一层。如果数据库这一层出现了问题,我们做的是数据库写失败,也不能够让其写成功,所以数据要一致。这时候对于数据一致又出现了新的问题,比如说我们按照买家订单写到各个单元里面,但是卖家如何发货呢?卖家其实是放到各个中心里面的,买家的所有下单数据都要同步到卖家这里。我们的模式就是最终一致性,就是对时间不是很敏感,我可以慢慢的同步,比如说,买家下了单,过了一两秒之后才能同步到卖家那里,其实这个时间是大家都能够接受的。对于强一致类型的数据,我们就跨单元,在同一个地点去捡数据。就是图上面红色部分——强中心依赖,所以这是我们交易链中核心——跨单元依赖。
个人凭感觉总结一下,拿购物的过程举个例子,正好也与上面的图符合:
首先水平进行了拆分,可以看到拆分成了不同的单元,每个单元里面有所有的商品数据,还有买家的个人数据,这样用户进行浏览商品目录,查看详情,下单等等所有的操作就可以局限在这一个单元里了,然后我们将这一个单元部署到北京,北京的用户就不用访问杭州的服务器了,直接访问北京的服务器就可以解决所有问题了。
基本逻辑是这样的,但是有这样几个问题,首先就是用户下单后,数据在北京的单元,另一个用户下单后数据在杭州的单元,商家该怎样知道到底多少人购买了呢,一般会搞一个中心单元,如上图所示,中心单元存储着所有买家下单的数据还有如卖家的全量数据、商品的全量数据,不同的单元会更新中心单元的数据,当买家在北京下单后,除了更新本单元,也会更新中心单元,这样从中间单元就知道买家的情况,然后根据买家发货了。至于更新中心单元是不是同步的就不清楚了,感觉不是同步的,上面隔一两秒才同步到卖家那里的意思感觉就是通过MQ这种异步同步到数据中心,但是要确保异步同步成功,不然一个北京单元挂了,北京用户一看我刚下的单怎么没了。
还有一些关键数据,如用户钱包余额、商品库存,这些所有单元都需要用的,也需要强数据一致性的,就都放在中心单元里,每个单元都取中心单元拿,不保存在私有单元里,对应上图的强中心依赖。
这就是我们整个异地多活的架构,异地多活解决的就是容灾问题、资源问题还有业务的扩展性问题。只要我们发现资源不够了,我们只需要创建一个新的单元,就可以把容量扩上去。首先调用就把资源统一了,建站平台通过调用就可以快速搭建一个单元。当这个单元通过全链路压测之后,我们整个单元就可以通入使用,这样容量的问题就得到了解决。那么容灾的问题通过全局路由就可以解决。当某个单元出了问题之后,我们只要快速的把流量切换出去就可以。业务扩展性是整个架构天然具备的,我们已经在千里之外把这个单元部署过了。
后面有一点内容说了下全链路压测和高可用,这个内容不多,本人也不大熟,就没写,感兴趣的可以打开博客开头的地址自己去看看。
第五章 新起点
为什么没有淘宝5.0,而要叫新起点呢?我想是因为年轻人不讲5的,阿里的团队2017年就预言到2020年要发生的事情,真是佩服佩服(狗头)。
云会变成如同水电煤一样的基础资源,越来越多的业务会在云上展现,这些业务中会有很多经历如同淘宝一样的发展,我们将加速这些业务的发展进程,创造更大价值,用技术驱动业务,把我们的技术能力输出到云上去。
现在我们不只服务于我们的双十一,我们也想为其它企业提供技术服务,用技术驱动他们,让他们也能只关心业务就好,不用去过多的关心底层是如何实现的。上面是一些在云端的产品,在阿里云上可以直接看到,像DRDS、EDAS、MQ等。
现在整理阿里的架构叫Aliware。Aliware已经在云上为企业提供企业级的互联网架构,支持了很多的企业。
分析:
这个就是说了云化,其实上面提到了很多中间件,如MQ、RPC、分布式数据库中间件、文件服务器等等,这种其实每个大项目都要用到的,每一个系统都搭建个集群就比较麻烦,可以抽出来组成一套系统,也就是所谓的云,不但可以更加专业化,还可以提供给各种不同的项目,甚至别的企业项目,让开发人员只需专注于业务的实现。据说淘宝很多都已经上云了,好像比较重要的支付系统也上云了,这个就不大清楚了,有感兴趣的可以自己去看看哈。
个人还是挺喜欢的,我之前还自己搭了一套RocketMQ集群,现在一想感觉血亏,有点浪费时间,还不如搞套阿里云上的,方便也没几个钱,溜了溜了。