https://yq.aliyun.com/articles/161190前端
摘要: 首届阿里巴巴中间件技术峰会上,阿里巴巴中间件技术部专家唐三带来“阿里电商架构演变之路”的演讲,本文从阿里业务和技术架构开始引入,分别分享了阿里电商从1.0到4.0架构的演变之路,着重分析了分布式和异地多活的改变之路。数据库
首届阿里巴巴中间件技术峰会上,阿里巴巴中间件技术部专家唐三带来“阿里电商架构演变之路”的演讲,本文从阿里业务和技术架构开始引入,分别分享了阿里电商从1.0到4.0架构的演变之路,着重分析了分布式和异地多活的改变之路。后端
视频回顾缓存
如下是精彩内容整理:服务器
阿里已经不仅仅有电商业务,今天咱们涉猎的很是普遍,布局也很是多。阿里从一家电商公司开始,若是业务已经覆盖到了各个行业,图为2015年的布局。按照这样的业务发展速度,若是没有一套完整的技术体系支撑,势必会影响整个业务的发展。markdown
能够看到咱们的技术是分层的,在最上的是业务,中间部分是中间件、搜索和大数据等中台系统。整个的大中台体系就是中中间这层通用的技术可以快速支持上层业务的快速发展。只要是用发中台的技术体系,都可以在上面快速的搭建本身的业务。架构
整个中台包括部分如图,除了中间件、搜索,还有一些数据分析。中间件在业务研发的过程当中起到很是重要的做用。这是在咱们整个技术架构演变过程当中,逐渐造成的一套体系。并发
淘宝从初创开始到今天,咱们的技术架构整体上经历了四代:oracle
那么接下来,我就从0开始,跟你们分享这一段历程。框架
LAMP结构
整个淘宝网从开始想去建立,到真正上线,总共经历了一个多月的时间。那这一个多月的时间都作了些什么呢?
第一件事情,咱们开始作技术选型,决定咱们后续怎么发展;第二件事情,如何在一个多月的时间,让咱们的网站上线。
咱们购买了一套基于LAMP架构的电商网站,而且拿到源代码,咱们对其进行二次开发,好比界面的UI改动,上下title的改动,其中最大的改动就是咱们对它的数据库作了读写分离。
Java架构
随着业务量的增加,就会发现一些瓶颈,主要来自于数据库。当时的数据库是MySQL4,还不够稳定,数据库常常会出现死机。所以,咱们直接把数据库换成oracle,经过PHP和oracle直接去链接进行操做,但PHP不支持链接池,即便使用一些开源的PHP中间件,让PHP去链接oracle,仍是很是不稳定,链接池的中间件常常卡死。
而后咱们开始考虑将技术体系转成Java,由于Java在企业级的应用中,有着比较成熟的生态。转化的过程当中也仍是很坎坷的:第一,咱们是一个线上正在运行的系统;第二,系统当时正在大规模的增加。因此说把系统替换成Java,最好的方法就是分块替换。同时发现,oracle的写入量仍是比较大的,当时还作了一个search,把产品搜索和店铺搜索放到search里面,这样每一次的请求都打到数据库里面了,这样咱们就完成了1.0架构到2.0架构的演进。
分布式架构
随着整个业务的发展,咱们又迎来了新问题,洪峰流量给咱们带来了巨大的挑战,电商行业在国内已经逐步开始盛行,咱们的流量直线上涨,电商的人口红利也开始上涨。随着流量的上涨,咱们面临着服务器和数据库的压力。
从技术角度来看,咱们面临着两个问题:
首先是淘宝上描述商品的图片特别多,图片问题很是严重,主要取决于咱们采用的是商用存储,成本很是高,最高级别版本也很难存储下咱们全部的图片;
其次在淘宝上浏览的全部交易都有交易快照,这也是很是耗费存储成本的;
第三,虽然数据库替换成了oracle,随着数据量的增大,咱们全部的请求都打到数据库上面,这时数据库的存储也快达到了极限,压力也很是大。
因此咱们开始对架构升级。第一,咱们增长了内存cache,cache主要是解决数据库压力过大的问题,咱们本身研制了一套Key/Value 分布式缓存(TAIR),就是在数据库前端加了一个内存cache,缓解了咱们数据库的压力。第二,咱们增长了分布式文件系统(TFS),以前的文件系统在商用的时候,成本过高,服务器的量很是大,因此咱们研发了本身的一套文件系统。
随着咱们的业务量逐渐增大,人也愈来愈多,这就致使开发维护成本特别高,当时咱们是all-in-one系统,全部人改全部的代码都是在这一个系统里面,就会出现如下问题:
还有性能问题。随着前端业务量的增大,服务器逐渐增多的时候,oracle也出现了链接数的瓶颈。因此咱们必须开始作新的架构,让整个架构往前走一步。
因而,咱们迈向了3.0架构。系统进行拆分变小,拆分系统主要是把系统分层。把系统分红三类:
第一类是c类,是中心类,好比说会员、商品、店铺等等,基于这些中心上面开发各自的系统。好比说商品详情、交易下单;
还有一些公共的类,是p类,好比交易平台,这是从业务上进行拆分。几个比较知名的项目,好比千岛湖项目(拆分出交易中心、类目属性中心)、五彩石项目(拆分出店铺中心、商品中心、评价中心)。
伴随着技术架构的改动,咱们的业务结构也开始进行改动,开始成立了相应的团队。上图的下半部分就介绍了咱们架构的演变过程。开始时,是all in one,1~10在维护一个项目。第二个阶段是10~1000人维护的MVC架构,实现了先后端分离,各司其职。第三个阶段是RPC,就是把各个系统进行拆分,而后各个系统之间进行通讯。第四个阶段就是SOA这样一个模式。
重点分享RPC的发展历程。咱们把应用拆成才c类、p类、垂直团队类。这些应用原本就是在一个大应用里面,他们之间能够很天然地进行通讯,能够直接进行相互调用。可是拆分以后,咱们的应用如何进行相互调用?
咱们开发了轻量级的HSF框架,它是基于Java interface 的RPC框架,使得开发系统时就像开发本地应用同样去正常的调用Java。使用这个框架能够真正远程的调用到其余的系统上面。
随着应用逐渐发展,咱们会依赖中间件或者各个产品之间相互依赖。为了解决Jar包冲突的问题,咱们研究出了Pandora容器。这个容器能把全部的加包作隔离,当发生Jar包冲突的时候,它知道优先加载哪一个,这样,咱们就把Jar包冲突的问题解决了,那服务发现怎么办呢?好比:一个应用A如何知道应用B里面有多少台机器呢,你的ip又是什么?最简单的方式就是静态列表,记录下ip,作轮询策略,先调用A的1号机,再调用2号机。这样就无法实现一个动态的发现。因此在这个过程当中,咱们有一个动态的配置中心(configserver),在你服务上线的时候,做为provider把服务放到configserver上去,当须要消费这个服务的时候,会看哪些服务能够调用,而后把这个列表拿到。Configserver会自动把相应的provider的ip推送到consumer上面。而后consumer会自动发现provider的服务,而后彼此会发生一个相互调用关系。若是configserver挂掉以后,你的provider是挂不上去的,可是已经发上去的服务是不受影响的,由于configserver已经把相应的服务推送到consumer上面。当咱们把分布式系统变得庞大以后,其实各个系统各司己职就行了。
Oracle其实也产生了性能瓶颈,而MySQL通过了多年发展,已经很是的成熟和稳定了。咱们考虑把数据库作拆分,也就是去IOE。对MySQL进行拆分,其实就是按照必定的规则去分库分表。拆分首先就是读写分离,而后作垂直拆分,还有水平拆分。垂直拆分主要是按业务来拆分,当垂直拆分到必定程度以后,有一些大业务仍是不能承担这样的数据量,咱们只能水平作分库分表,作sharding的拆分。分库分表就基于某一些主键算,若是主键符合什么样的条件,就Sharding到什么服务器上面。可是让每个业务系统去作的成本是很是高的,必定要有一个中间通用的东西,可以解决数据库水平拆分的问题。
因此咱们开发了一套数据库的中间件叫TDDL。TDDL就是在中间件层面支持数据库的水平拆分,业务就是在写单库同样,你不须要感知太多的东西,可是我已经把数据分散到各个数据库里面去了。当时还有一个系统是CORONA,CORONA今天咱们已经把他放到云上面去了,它遵循标标准的JDBC协议,应用在写代码的时候仍是遵循标准的JDBC协议,彻底不须要感知任何的东西,用的也是标准的JDBC包。把请求送到咱们的server上面,server去作Sharding处理,整个对应用是彻底没有感知的。
有了分库分表,咱们如何把oracle的数据迁移到MySQL?对此,咱们开发了几个中间件,第一个就是“愚公”,把oracle里面的数据经过“愚公”一点一点地迁移到MySQL里面去,放到各个库里面,同时保证咱们的业务不受影响;当咱们把数据库作分库分表以后,咱们还须要在数据库和缓存之间作一些trigger,当数据变了,须要触发一个事件,可能之前咱们须要经过写一个程序来实现,如今咱们也沉淀了一套中间件系统——精卫,它会监听每一个数据库的变化,当数据库每一个记录发生变化以后,它就触发一个事件,接听到这个事件以后,业务方能够根据本身的业务需求写一个精卫的worker,而后放到精卫里面去,触发相应的逻辑。最典型的就是触发cache逻辑。随着咱们IDC架构以后,当咱们的数据在单点写完以后,其余的地域如何感知到数据的变化呢?就是经过精卫这样一个系统实现的。当数据库变化了,精卫会触发失效cache,当业务请求再过来的时候,就会把cache里面的数据填充成最新的数据,而后可以让业务看到最新的数据,就不会出现当A单元数据变更了,而后B单元和C单元的cache没有生效的状况。
先是垂直拆分后是水平拆分,接下来就是对应用的拆分。应用拆分是经过HSF这个RPC框架解决应用之间的调用,解决同步调用,接下来还有异步调用。例如,我要建立一个订单,订单后面依赖了200多个系统,若是按照同步调用一步步进行下去,可能最终返回的返回时间会很是长,这时候怎么办呢?咱们会选择并发,A去调用B、去调用C、去调用D的这种HSF直接调用。但这时存在一个问题,若是说下游依赖的200多个系统中有一个系统被挂起了,就使整个请求被挂起了,而后接下来就很难进行了,并且这时若是对方的系统出现了严重的问题,会使我后续的请求都被挂起,最终也会把个人系统拖垮。这个时候咱们须要一个异步解耦的方式,那么就产生了消息中间件。消息中间件就是当A要去调用的时候,而后就会发一个消息,而后下游的系统开始订阅这条消息,各自去处理各自的,处理完以后把结果返回给中间件,这样就完成了异步通讯过程。那么若是其中某一个系统发生了问题,前端的交易系统建立订单的时候,它只要把消息发出去就不用管了,等全部的事情都处理完再回调它就能够了,就不会关注你如何调用。
图为分布式消息的处理过程。在内部咱们主要用的消息是NOTIFY/METAQ。如今咱们整体上都会在一个消息中间件上合并,其实并不须要这么多的中间件。应用场景就是分布式最终一致性、应用解耦、异步、并行等一系列问题。从整个物理部署也能够看出来,每一个都是集群的,有name server、producer、consumer等,这又解决了一个稳定性问题。咱们单点没有这个问题,随便一个server挂掉,其实咱们整个仍是能够通讯的,不会影响到业务的稳定性。
随着咱们整个分布式架构的演进,架构变得异常复杂,依赖关系也变得异常复杂。这时候咱们就想能不能可视化线上的问题,方便咱们知道究竟发生了什么、它们之间的调用关系和调用链路是什么样。因而乎就产生了分布式追踪(EAGLEEYE)。
有了EAGLEEYE,咱们就能清楚地知道一个请求过来,是怎么样从入口一直传递到最后,中间都经历了什么,而后哪一块多是有问题的。像图中这样报错位置会标红,咱们就能够清晰的知道是哪一个系统出的问题。咱们不须要再像之前同样,你们各在排查本身的系统,致使咱们处理问题的时间比较长。
异地多活
咱们整个架构演进到了4.0架构,其实到分布式架构看似咱们已经解决掉了业务上的问题。可是,咱们会遇到新的问题,好比说资源问题、业务扩展性还有就是容灾问题。资源中最重要的问题就是资源受限,当咱们的机房都在一个地方,这个地方并不能无限扩展,随着咱们服务器数量愈来愈多,那么这个地方可能就放不下咱们的服务器。好比2013年咱们买到机器以后,杭州的机房没有地方去放。随着咱们搞双十一活动,伴随着销售额和秒级峰值都有很大的提高,咱们的成本也会有必定的提高,咱们最终也会遇到单地域资源的限制;第二个是扩展性,有些业务可能不能只在这一个地方部署,由于别人访问我会比较慢,须要部署到国外,这时候业务有一个异地部署的需求;第三个就是一个容灾的需求,毕竟天灾人祸都在所不免。好比说一样是在2013年,杭州是40度的高温,咱们的机房差点被限电,还好最终没有限。可是这也给了咱们一个警示,就是咱们必需要对咱们的架构进行演进。若是不演进的话,总有一天咱们的资源会不够。
架构演进就是不把鸡蛋放到同一个篮子里面,咱们开始把咱们的业务划分出各个逻辑的单元,能够把它们放到各个地方,而后让咱们整个系统分散到全球,各个系统之间也没有过强的依赖,当某一个地域出现问题以后,不会影响到其余地方,咱们只须要把流量切换一下就能够。如今咱们应用的就是这套架构。
咱们按照业务的维度,把业务划分红各个逻辑单元。好比说第一个要作单元化的是交易单元,咱们就把整个交易链路划分出来,放到各个逻辑单元里面,而后在水平方向上进行拆分,而后把数据再在水平上作一个区分。单元内的数据就不要发跨单元。若是跨单元就会出现一些问题,好比说容灾问题,若是A挂掉以后,可能不止影响到A,其余单元也会受到影响。若是发生跨单元调用,延时也会比较长,对于最终用户下单的体验也是很是差的。因此咱们要遵循单元封闭的逻辑,让每个单元内的调用关系都封闭在本身的单元内,不要发生跨单元。
在技术架构上,咱们对技术作了一个分层,而且定了几个原则,除了单元封闭原则以外,还有全局路由,全局路由解决的是全局用户流量的分配,当一个用户流量进来以后,它会按照咱们的路由规则分配到相应的单元里面去。当用户流量进来,会跳到CDN,CDN知道其属于哪一个单元。而后到了某一单元以后,接入层会判断其是否属于这个单元,若是不属于,会让其跳到正确的单元里面去。若是属于这个单元就继续往下走,直到走到数据库这一层。若是数据库这一层出现了问题,咱们作的是数据库写失败,也不可以让其写成功,因此数据要一致。这时候对于数据一致又出现了新的问题,好比说咱们按照买家订单写到各个单元里面,可是卖家如何发货呢?卖家实际上是放到各个中内心面的,买家的全部下单数据都要同步到卖家这里。咱们的模式就是最终一致性,就是对时间不是很敏感,我能够慢慢的同步,好比说,买家下了单,过了一两秒以后才能同步到卖家那里,其实这个时间是你们都可以接受的。对于强一致类型的数据,咱们就跨单元,在同一个地点去捡数据。就是图上面红色部分——强中心依赖,因此这是咱们交易链中核心——跨单元依赖。
咱们整个单元化的项目经历了三年。2013年咱们开始在杭州作了两个POC验证,验证一下同城按照这种逻辑单元隔离开来,看看可否调用成功。2014年咱们在杭州、上海近距离的两个城市之间作了异地多活的尝试。2015年咱们开始在千里以外的地域去部署三地四单元架构,其中一个单元是云单元,这是咱们为了下降成本,咱们开始使用云机器来搞咱们双十一的大促。到2016年、2017年咱们的单元数愈来愈多,分布的愈来愈广,每个单元均可以作一些相应的尝试。
这就是咱们整个异地多活的架构,异地多活解决的就是容灾问题、资源问题还有业务的扩展性问题。只要咱们发现资源不够了,咱们只须要建立一个新的单元,就能够把容量扩上去。首先调用就把资源统一了,建站平台经过调用就能够快速搭建一个单元。当这个单元经过全链路压测以后,咱们整个单元就能够通入使用,这样容量的问题就获得了解决。那么容灾的问题经过全局路由就能够解决。当某个单元出了问题以后,咱们只要快速的把流量切换出去就能够。业务扩展性是整个架构自然具有的,咱们已经在千里以外把这个单元部署过了。
高可用问题也是咱们面临的一个比较大的问题,在2013年之前双十一前几分钟的成功率是很低的,不少人是没法购物的。可是在2013年以后,经过全链路压侧这样一个技术,可以提早模拟双十一零点这一刻的洪峰流量,使得咱们可以提早把问题解决掉,因此说整个购物体验愈来愈顺滑。高可用在整个双十一备战过程当中起到一个很是核心的做用。
当咱们的业务在分布式和异步化以后,并且流量猛烈上涨以后,咱们遇到的最大问题是容量评估:就是我也不知道我须要准备多少机器来抗这些流量,我也不知道我上下游依赖的应用应该准备多少流量,由于我根本不太清楚咱们之间详细的调用是什么样子的。用户来的时候不一样的调用链路可能调用彼此的次数不同,因此说容量是很难评估的。因此咱们首先模拟双十一零点这一时刻的流量,把这个流量制造出来,看一下场景。经过咱们制造的数据,提早把咱们双十一的问题暴漏出来。
高可用体系自己就是一套体系,它们之间彼此依赖,是闭环的。好比说咱们一个单元的容量只有十万,当我容量超过十万的时候该怎么办呢?其实在双十一的时候,若是数据超过十万,系统会出现一个页面告诉你正在排队——限流。限流是怎么产生的呢?其实就是为了使咱们可以更好的服务于咱们可以服务的用户范围。对一个业务设定了一个阈值以后,当流量超过了阈值,就开始进行限流。这个时候若是我想提高本身的弹性,应该把那些没有达到的阈值、也就是水位比较低的应用,把它的机器弹过来,弹到水位比较高的应用。
除了这些以外,其实咱们的高可用还有不少,好比说关于容量能力,我刚才提到了压测,全链路和单链路,还有线上的单机压测,容量评估。静态架构有灰度发布、Eagleeye跟踪。运行态有xflush/alimonitor、业务防止损BCP/DCP/Holo、限流降级Sentinel、开关平台Switch、预案系统Preplan、流量调度Failover等,还有应用资源管理应用弹性伸缩Athena、资源调度Zeus、运行环境隔离Moses等。这样咱们高可用体系就造成一个闭环。其中一个场景就是,好比咱们进行压测,这边会限流,这该怎么办呢?这时候弹性开始往外弹,把整个水位调匀,这样会使咱们经过压测。第二个场景就是当我一个应用挂了以后,我把流量切到另一个地方去了,就去触发限流,若是这时候咱们还有资源,咱们应该利用弹性,把水位弹上来。
新起点
云会变成如同水电煤同样的基础资源,愈来愈多的业务会在云上展示,这些业务中会有不少经历如同淘宝同样的发展,咱们将加速这些业务的发展进程,创造更大价值,用技术驱动业务,把咱们的技术能力输出到云上去。
如今咱们不仅服务于咱们的双十一,咱们也想为其它企业提供技术服务,用技术驱动他们,让他们也能只关心业务就好,不用去过多的关心底层是如何实现的。上面是一些在云端的产品,在阿里云上能够直接看到,像DRDS、EDAS、MQ等。
如今整理阿里的架构叫Aliware。Aliware已经在云上为企业提供企业级的互联网架构,支持了不少的企业。