时间过得很快,来淘宝已经两个月了,在这两个月的时间里,本身也感觉颇深。下面就结合淘宝目前的一些底层技术框架以及本身的一些感触来讲说如何构建一个可 伸缩,高性能,高可用性的分布式互联网应用。apache
相关专题:淘宝双11背后高并发技术讨论后端
一 应用无状态(淘宝session框架)浏览器
俗话说,一个系 统的伸缩性的好坏取决于应用的状态如何管理。为何这么说呢?我们试想一下,假如咱们在session中保存了大量与客户端的状态信 息的话,那么当保存状态信息的server宕机的时候,咱们怎么办?一般来讲,咱们都是经过集群来解决这个问题,而一般所说的集群,不只有负载均衡,更重要的是要有失效恢复failover,好比tomcat采 用的集群节点广播复制,jboss采 用的配对复制等session状 态复制策略,可是集群中的状态恢复也有其缺点,那就是严重影响了系统的伸缩性,系统不能经过增长更多的机器来达到良好的水平伸缩,由于集群节点间session的 通讯会随着节点的增多而开销增大,所以要想作到应用自己的伸缩性,咱们须要保证应用的无状态性,这样集群中的各个节点来讲都是相同的,从而是的系统更好的水平伸缩。缓存
OK,上面说了无状态的重要性,那么具体如何实现无状态呢?此时一个session框架就会发挥做用了。幸运的是淘 宝已经具备了此类框架。淘宝的session框架采用的是client cookie实现,主要将状态保存到了cookie里 面,这样就使得应用节点自己不须要保存任何状态信息,这样在系统用户变多的时候,就能够经过增长更多的应用节点来达到水平扩展的目的.但 是采用客户端cookie的 方式来保存状态也会遇到限制,好比每一个cookie通常不能超过4K的大小,同时不少浏览器都限制一个站点最多保存20个cookie.淘 宝cookie框 架采用的是“多值cookie”, 就是一个组合键对应多个cookie的 值,这样不只能够防止cookie数 量超过20, 同时还节省了cookie存 储有效信息的空间,由于默认每一个cookie都会有大约50个字节的元信息来描述cookie。tomcat
除了淘宝目前的session框 架的实现方式之外,其实集中式session管理来完成,说具体点就是多个无状态的应用节点链接一个session 服 务器,session服 务器将session保 存到缓存中,session服 务器后端再配有底层持久性数据源,好比数据库,文件系统等等。安全
二 有效使用缓存(Tair)cookie
作互联网应用的兄弟应该都清楚,缓存对于一个互联网应用是多么的重要,从浏览器缓存,反向代理缓存,页面缓存,局部页面缓存,对象缓存等等都是缓存应用的场景。网络
一 般来讲缓存根据与应用程序的远近程度不一样能够分为:local cache 和 remote cache。 通常系统中要么采用local cache,要么采用remote cache,二者混合使用的话对于local cache和remote cache的数据一致性处理会变 大比较麻烦.
在大部分状况下,我 们所说到的缓存都是读缓存,缓存还有另一个类型:写缓存. 对 于一些读写比不高,同时对数据安全性需求不高的数据,咱们能够将其缓存起来从而减小对底层数据库的访问,好比 统计商品的访问次数,统 计API的 调用量等等,可 以采用先写内存缓存而后延迟持久化到数据库,这样能够大大减小对数据库的写压力。
OK,我以店铺线的系统为例,在用户浏览店铺的时候,好比店铺介绍,店铺交流区页面,店铺服务条款页面,店铺试衣间页面,以及店铺内搜索界面这些界面更新不是很是频繁,所以适合放到缓存中,这样能够大大减低DB的负载。另外宝贝详情页面相对也更新比较 少,所以也适合放到缓存中来减低DB负载。
三 应用拆分(HSF)
首先,在说明应用拆分以前,咱们先来回顾一下一个系统从小变大的过程当中遇到的一些问题,经过这些问题咱们会发现拆分对于构建一个大型系统是如何的重要。
系统刚上线初期,用户数并很少,全部的逻辑也许都是放在一个系统中的,全部逻辑跑到一个进程或者一个应用当中,这个时候由于比较用户少,系统访问量低,所以将所有的逻辑都放在一个应用何尝不可。可是,兄弟们都清楚,好景不长,随着系统用户的不断增长,系统的访问压力愈来愈多,同时随着系统发展,为了知足用户 的需求,原有的系统须要增长新的功能进来,系统变得愈来愈复杂的时候,咱们会发现系统变得愈来愈难维护,难扩展,同时系统伸缩性和可用性也会受到影响。那么这个时候咱们如何解决这些问题呢?明智的办法就是拆分(这也算是一种解耦),咱们须要将原来的系统根据必定的标准,好比业务相关性等分为不一样的子系统, 不一样的系统负责不一样的功能,这样切分之后,咱们能够对单独的子系统进行扩展和维护,从而提升系统的扩展性和可维护性,同时咱们系统的水平伸缩性scale out大 大的提高了,由于咱们能够有针对性的对压力大的子系统进行水平扩展而不会影响到其它的子系统,而不会像拆分之前,每次系统压力变大的时候,咱们都须要对整个大系统进行伸缩,而这样的成本是比较大的,另外通过切分,子系统与子系统之间的耦合减低了,当某个子系统暂时不可用的时候,总体系统仍是可用的,从而整 体系统的可用性也大大加强了。
所以一个大型的互联网应用,确定是要通过拆分,由于只有拆分了,系统的扩展性,维护性,伸缩性,可用性才会变的更好。可是拆分也给系统带来了问题,就是子系统之间如何通讯的问题,而具体的通讯方式有哪些呢?通常有同步通讯和异步通讯,这里咱们首先来讲下同步通讯,下面的主题“消息系 统”会说到异步通讯。既然须要通讯,这个时候一个高性能的远程调用框架就显得很是总要啦,所以我们淘宝也有了本身的HSF框 架。
上 面所说的都是拆分的好处,可是拆分之后必然的也会带来新的问题,除了刚才说的子系统通讯问题外,最值得关注的问题就是系统之间的依赖关系,由于系统多了,系统的依赖关系就会变得复杂,此时就须要更好的去关注拆分标准,好比可否将一些有依赖的系统进行垂直化,使得这些系统的功能尽可能的垂直,这也是目前淘宝正 在作的系统垂直化,同时必定要注意系统之间的循环依赖,若是出现循环依赖必定要当心,由于这可能致使系统连锁启动失败。
OK,既然明白了拆分的重要性,咱们看看随着淘宝的发展,淘宝自己是如何拆分系统的。
首先咱们来看如下这个图:(做者图片已没法打开,请见谅)
从上面的图能够看出淘宝系统的一个演变过程,在这个演变的过程当中,咱们所说的拆分就出现V2.2和V3.0之 间。在V2.2版 本中,淘宝几乎全部的逻辑都放在(Denali)系统中,这样致使的问题就是系统扩展和修改很是麻烦,而且更加致命的是随着淘宝业务量的增长,若是按照V2.2的架构已经没有办法支撑之后淘宝的快速发展,所以你们决定对整个系统进行拆分,最 终V3.0版本的淘宝系统架构图以下:(做者图片已没法打开,请见谅)
从上图能够看出V3.0版 本的系统对整个系统进行了水平和垂直两个方向的拆分,水平方向上,按照功能分为交易,评价,用户,商品等系统,一样垂直方向上,划分为业务系统,核心业务系统以及以及基础服务,这样以来,各个系统均可以独立维护和独立的进行水平伸缩,好比交易系统能够在不影响其它系统的状况下独立的进行水平伸缩以及功能扩展。
从上面能够看出,一个大型系统要想变得可维护,可扩展,可伸缩,咱们必须的对它进行拆分,拆分必然也带来系统之间如何通讯以及系统之间依赖管理等问题,关于通讯方面,淘宝目前独立开发了本身的高性 能服务框架HSF, 此框架主要解决了淘宝目前全部子系统之间的同步和异步通讯(目前HSF主要用于同步场合,FutureTask方 式的调用场景还比较少)。至于系统间的依赖管理,目前淘宝还作的不够好,这应该也是咱们之后努力解决的问题。
四 数据库拆分(TDDL)
在前面“应用拆分”主题中,咱们提到了一个大型互联网应用须要进行良好的拆分,而那里咱们仅仅说了”应用级别”的拆 分,其实咱们的互联网应用除了应用级别的拆分之外,还有另一个很重要的层面就是存储如何拆分的。所以这个主题主要涉及到如何对存储系统,一般就是所说的RDBMS进 行拆分。
好了,肯定了这个小节的主题以后,咱们回顾一下,一个互联网应用从小变大的过程当中遇到的一些问题,经过遇到的问题来引出咱们拆分RDBMS的 重要性。
系 统刚开始的时候,由于系统刚上线,用户很少,那个时候,全部的数据都放在了同一个数据库中,这个时候由于用户少压力小,一个数据库彻底能够应付的了,可是随着运营那些哥们辛苦的呐喊和拼命的推广之后,忽然有一天发现,oh,god,用户数量忽然变多了起来,随之而 来的就是数据库这哥们受不了,它终于在某一天你们都和惬意的时候挂掉啦。此时,我们搞技术的哥们,就去看看到底是啥缘由,咱们查了查之后,发现原来是数据库读取压力太大了,此时我们都清楚是到了读写分离的时候,这个时候咱们会配置一个server为master节 点,而后配几个salve节 点,这样以来经过读写分离,使得读取数据的压力分摊到了不一样的salve节点上面,系统终于又恢复了正常,开始正常运行了。可是好景仍是不长,有一天咱们发现master这哥们撑不住了,它负载老高了,汗 流浃背,随时都有翘掉的风险,这个时候就须要我们垂直分区啦(也就是所谓的分库),好比将商品信息,用户信息,交易信息分别存储到不一样的数据库中,同时还能够针对商品信息的库采用master,salve模式,OK, 经过分库之后,各个按照功能拆分的数据库写压力被分担到了不一样的server上面,这样数据库的压力终于有恢复到正常状态。可是是否是这样,咱们就能够高枕无忧了呢?NO,这个NO, 不是我说的,是前辈们经过经验总结出来的,随着用户量的不断增长,你会发现系统中的某些表会变的异常庞大,好比好友关系表,店铺的参数配置表等,这个时候不管是写入仍是读取这些表的数据,对数据库来讲都是一个很耗费精力的事情,所以此时就须要咱们进行“水平分区”了(这就是俗话说的分表,或者说sharding).
OK,上 面说了一大堆,无非就是告诉你们一个事实“数据库是系统中最不容易scale out的一层”,一个大型的互联网 应用必然会通过一个从单一DB server,到Master/salve,再到垂直分区(分库),而后再到水平分区(分表,sharding)的过程,而在这个过程当中,Master/salve 以 及垂直分区相对比较容易,对应用的影响也不是很大,可是分表会引发一些棘手的问题,好比不能跨越多个分区join查 询数据,如何平衡各个shards的 负载等等,这个时候就须要一个通用的DAL框架来屏蔽底层数据存储对应用逻辑的影响,使得底层数据的访问对应用透明化。
拿淘宝目前的状况来讲,淘宝目前也正在从昂贵的高端存储(小型机+ORACLE)切换到MYSQL,切 换到MYSQL以 后,势必会遇到垂直分区(分库)以及水平分区(Sharding)的问题,所以目前淘宝根据自 己的业务特色也开发了本身的TDDL框架,此框架主要解决了分库分表对应用的透明化以及异构数据库之间的数据复制
五 异步通讯(Notify)
在”远 程调用框架”的 介绍中,我 们说了一个大型的系统为了扩展性和伸缩性方面的需求,确定是要进行拆分,可是 拆分了之后,子 系统之间如何通讯就成了咱们首要的问题,在”远程调用框架”小节 中,我 们说了同步通讯在一个大型分布式系统中的应用,那么这一小节咱们就来讲说异步通讯.好了,既 然说到了异步通讯,那 么”消 息中间件”就 要登场了,采 用异步通讯这其实也是关系到系统的伸缩性,以及最大化的对各个子系统进行解耦.
说 到异步通讯,咱们须要关注的一点是这里的异步必定是根据业务特色来的,必定是针对业务的异步,一般适合异步的场合是一些松耦合的通讯场合,而对于自己业务上关联度比较大的业务系统之间,咱们仍是要采用同步通讯比较靠谱。
OK,那 么下一步咱们说说异步能给系统带来什么样子的好处。首先咱们想一想,假如系统有A和B两个 子系统构成,假如A和B是 同步通讯的话,那么要想使得系统总体伸缩性提升必须同时对A和B进行 伸缩,这就影响了对整个系统进行scale out.其次,同步调用还会影响到可用性,从数学推理的角度来讲,A同 步调用B, 若是A可 用,那么B可 用,逆否命题就是若是B不 可用,那么A也 不可用,这将大大影响到系统可用性,再次,系统之间异步通讯之后能够大大提升系统的响应时间,使得每一个请求的响应时间变短,从而提升用户体验,所以异步在提升了系统的伸缩性以及可用性的同时,也大大的加强了请求的响应时间(固然了,请求的整体处理时间也许不会变少)。
下面咱们就以淘宝的业务来看看异步在淘宝的具体应用。交易系统会与不少其它的业务系统交互,若是在一次交易过程当中采用同步调用的话,这就要求要向交易成功,必须依赖的全部系统均可用,而若是采用异步通讯之后,交易系 统借助于消息中间件Notify和 其它的系统进行了解耦,这样以来当其它的系统不可用的时候,也不会影响到某此交易,从而提升了系统的可用性。
最后,关于异步方面的讨论,我能够 推荐你们一些资源:
1 . J2EE meets web2.0
2. Ebay架构特色(HPTS 2009)
六 非结构化数据存储 ( TFS,NOSQL)
在 一个大型的互联网应用当中,咱们会发现并非全部的数据都是结构化的,好比一些配置文件,一个用户对应的动态,以及一次交易的快照等信息,这些信息通常不适合保存到RDBMS中, 它们更符合一种Key-value的 结构,另外还有一类数据,数据量很是的大,可是实时性要求不高,此时这些数据也须要经过另外的一种存储方式进行存储,另一些静态文件,好比各个商品的图片,商品描述等信息,这些信息由于比较大,放入RDBMS会引发读取性能问题,从而影响到其它 的数据读取性能,所以这些信息也须要和其它信息分开存储,而通常的互联网应用系统都会选择把这些信息保存到分布式文件系统中,所以淘宝目前也开发了本身的分布式文件系统TFS,TFS目 前限制了文件大小为2M, 适合于一些小于2M数 据的存放。
随 着互联网的发展,业界从08年 下半年开始逐渐流行了一个概念就是NOSQL。咱们都知道根据CAP理论,一致性,可用性和分区容错性3者 不能同时知足,最多只能同时知足两个,咱们传统的关系数据采用了ACID的事务策略,而ACID的 事务策略更加讲究的是一种高一致性而下降了可用性的需求,可是互联网应用每每对可用性的要求要略高于一致性的需求,这个时候咱们就须要避免采用数据的ACID事 务策略,转而采用BASE事 务策略,BASE事 务策略是基本可用性,事务软状态以及最终一致性的缩写,经过BASE事务策略,咱们能够经过最终一致性来提高系统的可用性,这也是目前不少NOSQL产品所采用的策略,包括facebook 的cassandra,apache hbase,google bigtable等,这些产品很是适合一些非结构化的数据,好比key-value形 式的数据存储,而且这些产品有个很好的优势就是水平伸缩性。目前淘宝也在研究和使用一些成熟的NOSQL产品。
七 监控、预警系统
对于大型的系统 来讲,惟一可靠的就是系统的各个部分是不可靠。
因 为一个大型的分布式系统中势必会涉及到各类各样的设备,好比网络交换机,普通PC机,各类型号的网卡,硬盘,内存等等,而这些东东都在数量很是多的时候,出现错误的几率也会变大,所以咱们须要时时刻刻监控系统的状态,而监控也有粒度的粗细之分,粒度粗一点的话,咱们须要对整个 应用系统进行监控,好比目前的系统网络流量是多少,内存利用率是多少,IO,CPU的 负载是多少,服务的访问压力是多少,服务的响应时间是多少等这一系列的监控,而细粒度一点的话,咱们就需对好比应用中的某个功能,某个URL的 访问量是多,每一个页面的PV是 多少,页面天天占用的带宽是多少,页面渲染时间是多少,静态资源好比图片天天占用的带宽是多少等等进行进一步细粒度的监控。所以一个监控系统就变得必不可少了。
前 面说了一个监控系统的重要性,有了监控系统之后,更重要的是要和预警系统结合起来,好比当某个页面访问量增多的时候,系统能自动预警,某台Server的CPU和 内存占用率忽然变大的时候,系统也能自动预警,当并发请求丢失严重的时候,系统也能自动预警等等,这样以来经过监控系统和预警系统的结合可使得咱们能快速响应系统出现的问题,提升系统的稳定性和可用性。
八 配置统一管理
一个大型的分布 式应用,通常都是有不少节点构成的,若是每次一个新的节点加入都要更改其它节点的配置,或者每次删除一个节点也要更改配置的话,这样不只不利于系统的维护和管理,同时也更加容易引入错误。另外不少时候集群中的不少系统的配置都是同样的,若是不进行统一的配置管理,就须要再全部的系统上维护一份配置,这样会 形成配置的管理维护很麻烦,而经过一个统一的配置管理可使得这些问题获得很好的解决,当有新的节点加入或者删除的时候,配置管理系统能够通知各个节点更新配置,从而达到全部节点的配置一致性,这样既方便也不会出错。