《淘宝技术这十年》读书笔记 (三). 创造技术TFS和Tair

        前面两篇文章介绍了淘宝的发展历程和Java时代的变迁:
            《淘宝技术这十年》读书笔记 (一).淘宝网技术简介及来源
            《淘宝技术这十年》读书笔记 (二).Java时代的脱胎换骨和坚若磐石
        马云说过“创新不是为了与对手竞争,而是跟明天竞争”,所以这篇文章讲述淘宝的创新技术TFS和Tair及创新的产品。
        该篇文章不仅仅对在读大学生非常有所帮助,因为你能从文章中看到很多你需要学习的知识,不仅仅包括数据库、计算机网络、操作系统、数据结构等基础课程;还根据时代的技术变迁讲述了当时最新的编程技术及应用,如数据挖掘、Java\Oracle、搜索引擎分词排序、分布式、大数据GFS、海量文件处理等,这些知识对你面试找工作都非常有帮助;同时也根据淘宝网发展历程不断讲述了它遇到的问题及解决方法。从最初的通过购买更高端的系统设备(如IOE——IBM小型机、OracleEMC存储)到最好的设备也不能满足淘宝网海量数据尤其是图片数据的存储需求,最后自己创造属于自己的针对海量小文件存储的文件系统,这些问题都很可能是你以后成为程序员或IT创业者将面临的问题。所以我才这么强烈的写这本书的读书笔记。
                                                                                           ——Eastmount

一. TFS

1.需要创新的原因

        在2.1版本终于稳定下来,淘宝网运行了这个版本的系统两年多的时间。这期间有很多优秀的人才加入,也开发了很多优秀的产品。如商品的类目属性、支付宝认证系统、招财进宝项目、淘宝旅行、淘宝论坛等。在这些产品和功能的最底层其实还是—— 商品管理和交易管理
        由于2.1版本产品7天或14天到期后会自动下架,商家需重新发布;重新商家的 产品ID 会变化产生新的商品信息,因为搜索引擎不知道同样的商品哪个排在前面,于是把挂牌时间长的排在前面,这就需要把老的商品下架,否则一直排在前面;同时由于存储限制不能让所有的商品总存放在主库中。
       这种处理方式简单粗暴,但还算公平。 不过这会导致很多需求都无法满足。 例如卖出一件商品之后就无法更改价格,否则前面已经成交的那个价格都变了,而且同样的商品,上一次销售后很多好评都无法在下一个商品上体现出来;再如,我买过的商品结束后只看到交易的信息,不知道卖家是否还会卖。
        基于这些需求,我们在2006年下半年把商品和交易拆开,一个商家的一种商品有一个唯一的ID,上下架都是同一个商品。 那么如果卖家修改价格和库存信息,已经成交的信息怎么处理?那就在买家每交易一次时都记录下商品的快照信息,有多少次交易就有多少个快照。这样买卖双方比较爽了,但给系统带来了什么?存储的成本大幅度上升了。
       存储的成本高到什么程度呢? 数据库方面用了 IOE ,一套千万级别;同时淘宝网还有很多文件需要存储,最主要的是图片、商品描述、交易快照。 一个商品包含几张图片和一长串的描述信息,而每张图片都有几张不同规格的缩略图。在2010年,淘宝网的后端系统上保存着286亿个图片文件。
         大家常说“无图无真相”,淘宝网热门商品图片的访问流量非常巨大。 在淘宝网整体流量中,图片的访问流量要占到90%以上,而且这些图片平均大小为17.45KB,小于8KB的图片占整体图片数量的61%。 这么多的图片数据、这么大的访问流量,给淘宝网系统带来了巨大的挑战。 对于大多数系统来说,最头疼的就是大规模的小文件存储与读取,因为磁头需要频繁寻道和换道,因此在读取上带来较长的延时。
        PS:平时大家拷贝2G的电影和2G的多张图片就很容易见到这种延时吧!
        在大量高并发访问量的情况下,简直就是系统的噩梦。我们该怎么办呢?
同样的套路,在某个规模下采用现有的商业解决方案,达到某种规模之后,商业的解决方案无法满足,此时只有 自己创造解决方案 了。
        对于淘宝网的图片存储来说,转折点在2007年。这之前一直采用商用存储系统,用的是 NetApp 公司的文件存储系统 。随着图片文件数量以每年3倍的速度增长,NetApp公司的存储系统从低端到高端不断迁移,直到2006年,NetApp公司最高端产品再也不能满足淘宝网存储的要求。
        2006 年开始,我们决定自己开发一套针对海量小文件存储的文件系统,用于解决自身图片存储的难题。这标志着淘宝网从使用技术到创造技术的阶段。
        2007年之前的图片存储架构如下图所示:(我表示看不懂)


        在一次架构师大会上,章文嵩博士总结几点商用存储系统的局限和不足。
        1.商用存储系统没有对小文件存储和读取环境进行有针对性的优化;
        2.文件数量大,网络设备无法支撑;
        3.整个系统所连接的服务器越来越多,网络连接数已经达到网络存储设备的极限;商用存储系统扩容成本高,10TB存储容量需要几百万元,而且容灾和安全性无法得到很好的保证。

2.图片存储系统TFS

       历史总是惊人的巧合,在我们准备研发文件存储系统的时候,Google走在了前面。2007年他们公布了GFS(Google File System)的论文,这给我们带来了很多借鉴的思路。随后我们开发出了适合淘宝网使用的图片存储系统(TaoBao File System,简称TFS)。3年之后,我们发现历史的巧合比我们想象的还要神奇,几乎跟我们同事中国的另一家互联网公司也开发了他们的文件存储系统,甚至命名都一样——TFS,太神奇了!
        PS:如果你对大数据、分布式、云计算、Hadoop\Spark这些技术比较了解的话,你一定也知道他们——Google的三架马车。2003年至2004年谷歌公司公布了关于GFS、MapReduce、BigTable三篇技术性论文,从此分布式系统、大数据、云存储、云计算这些相关知识如雨后春笋般出现。Google文件系统(GFS)是谷歌公司为了能存储以百亿计的海量网页信息而专门开发的文件系统,在Google整个云存储和云计算技术框架中,GFS是其他相关技术的基石。
        2007年6月,TFS正式上线运营。说到TFS的系统架构,首先要描述清楚业务需求,淘宝对图片存储的需求大概可以描述如下:文件较小;并发量高;读操作远大于写操作;访问随机;没有文件修改的操作;要求存储成本低;能容灾、备份。
        显然,应对这种需求时要用分布式存储系统;由于文件大小比较统一,可以采用专有文件系统;由于并发量高,读写随机性强,需要更少的I/O操作;考虑到成本和备份,需要用廉价的存储设备;考虑到容灾,需要能平滑扩容。
        参照GFS并做了大量的优化后,TFS1.0版架构图如下:

        从上面的架构图可看出:集群由一对Name Server和多态Data Server构成,Name Server的两台服务器互为双机,这就是集群文件系统中管理节点的概念。
        在这个系统中,每个Data Server运行在一台普通的Linux主机上;以Block文件的形式存放数据文件(一个Block的大小一般是64MB);Block存储多份是为了保证数据安全;利用ext3文件系统存放数据文件;磁盘raid5做数据冗余;文件名内置元数据信息,用户保存TFS文件名与实际文件的对照关系。
        淘宝TFS文件系统在核心设计上最大的取巧在于传统的集群系统中元数据只有一份,通常由管理节点来管理,很容易成为瓶颈。而对于淘宝网的用户,图片文件究竟用什么名字来保存,他们并不关心;因此,TFS在设计上考虑在图片的保存文件名上暗藏一些元数据信息,如图片大小、时间、访问频次等信息(所在逻辑块号)。而在实际的元数据上,保存的信息很少。
        因此,元数据结构非常简单,仅仅只需要一个FileID就能够准确定位文件在什么地方。由于大量的文件信息都隐藏在文件名中,整个系统完全抛弃了传统的目录树结构,因为目录树开销最大。拿掉后整个集群的高可扩展性可极大地提高。实际上这一设计理念和后来的“对象存储”较类似。
        TFS上线之前,淘宝网每个商品只允许上传一张图片,大小限定在120KB之内,在商品详情中的图片必须使用外站的服务,那时候发布一件商品确实非常麻烦。TFS上线后,商品展示图片开放到5张,商品描述里面的图片也可以使用淘宝的图片服务,目前为止淘宝网为每个用户提供了1GB的图片空间。技术和业务就是这么相互借力推动者的,业务满足不了的时候,技术必须创新,技术创新之后,业务有了更大的发展空间。

        TFS发布之后,又经历了多个版本的修改,到1.3版时已经比较成熟了,2009年6月TFS 1.3版本上线。
        TFS 1.3版本逻辑结构图如下图所示:


        在TFS 1.3版本中,重点改善了心跳和同步的性能,最新版本的心跳和同步在几秒钟之内就可完成切换,同时进行了一些新的优化,包括元数据存储在内存中、清理磁盘空间等。性能上也做了优化,整个图片服务机器的拓扑结构如下图所示:


        整个图片存储系统就像一个庞大的服务器,有处理单元、缓存单元和存储单元。前面介绍过后台的TFS集群文件存储系统,TFS前端,还部署着200多台图片文件服务器,用Apache实现,用于生成缩略图的运算。值得一提,根据淘宝网的缩略图生成规则,缩略图都是实时生成的。这样有两点好处:一是为了避免后端图片服务器上存储的图片数量过多,大大节约后台存储空间的需求,我们计算过,采用实时生成缩略图的模式比提前全部生成好缩略图的模式节约90%的存储空间。二是缩略图可根据需求实时生成更加灵活。
        图片文件服务器的前端则是一级缓存和二级缓存,前面还有全局负责均衡的设置,用于解决图片的访问热点问题。
        图片访问热点一定存在,重要的是让图片尽量在缓存中命中。目前淘宝网在各个运营商的中心点设有二级缓存,整体系统中心点设有一级缓存,加上全局负载均衡,传递到后端TFS的流量就已经非常均衡和分散了,大部分图片都尽量在缓存中命中。如果缓存中无法命中,则会在本地服务器上查找是否存有原因,并根据原因生成缩略图,如果都没有命中,则会去后台TFS集群文件存储系统上调取。因此,最终反馈到TFS集群文件存储系统上的流量已经被大大优化了。
        淘宝网将图片处理与缓存编写成基于Nginx的模块,Nginx是当时性能最高的HTTP服务器(用户空间),代码清晰,模块化很好。淘宝试用GraphicsMagick进行图片处理,采用了面向小对象的缓存文件系统,前端有LVS+Haproxy将图片和其所有缩略图请求都调度到同一台Image Server(图片服务器)。
        在文件定位上,内存用Hash算法做索引,最多一次读盘。另外会有很多相同的图片重复上传上来,去除重复文件也是采用Hash算法实现的。写盘方式采用Append方式写,并采用了淘汰策略FIFO,主要考虑降低硬盘的写操作,没必要进一步提高Cache命中率,因为ImageServer和TFS位于同一个数据中心,读盘效率非常高的。
        目前淘宝网的TFS已经开源(见code.taobao.org),业界的同仁可以一起使用和完善这个系统。

二. 那些年做过的产品

1.团购产品

        TFS的开发让淘宝的图片功能得到了充分发挥。同TFS一样,很多技术都是在产品的推动下得到发展的。在介绍下面的技术之前,有必要说说前些年我们做过的几个产品。
        先说一个比较悲剧的——“团购”,这个团购不是现在满大街的那种Groupon类型的模式,在那之前,2006年淘宝提出了“团购”这种产品。产品经理一灯设想是让买家在社区发起团购,“团长”找到足够的人后,去跟卖家砍价,类似于蘑菇街的“自由团”。但比较偏离的是做成了让卖家设置团购价,卖家达到一定数量后,以团购价成交。
        这种交易方式最大的弱点是让买家看到了卖家的底牌,即便达不到团购的数量,他们也往团购的价格上砍。当时为了提高流量,淘宝网开辟了团购专区,实诚的卖家在达不到团购数量时被砍价砍亏了,狡猾的卖家干脆提高原价,利用这个专区做促销。在接下来两年里,这个产品沦落成了促销工具(话说现在满大街的团购,其实也就是促销)。这个产品让研发人员对“产品”这个概念有了深刻的认识。

2.我的淘宝

        再说一个更加悲剧的——“我的淘宝”。它是给会员管理自己的商品、交易、收获地址、评价、投诉的地方,这个地方必须在登录之后才能看到,所以风格与外观完全不一样,很长时间都没有优化过,样子丑,用户操作也不方便,如果一个人有很多商品,上下架需要一个一个地操作,非常麻烦。
        这时候一个重要人物承志(现在的蘑菇街CEO)登场了,他给我们演示了最牛的前端交互技术,就是Gmail上那种AJAX的交互方式,可以拖动,可以用鼠标右键,也可以用组合键,操作完毕还不刷新页面,管理商品有如神助
        我是这个项目的项目经理,一灯是产品经理,我们干了三个月,快要完成的时候,老马突然出现在我身后,看我操作了一遍新版“我的淘宝”之后,问我这是不是客户端软件,我说是网页,他抓狂了,说这跟客户端软件一样,链接下面的下划线都没有,上下架用文件夹表示,他都不知道怎么操作,卖家也不会玩。


        页面如上图所示,看看这神乎其技的翻页条、精致的文件夹结构、人性化的多选框、还有一个类似Excel冻结窗口的功能。
        老马果然是神一样的人物,他说的应验了,淘宝历史上第一个群体性事件爆发,使用完新版本的“我的淘宝”之后,很多买家说不会玩儿。页面改得像网页一样,改了半个月愤怒还是没有平息;后来论坛上投票一半以上人反对,于是把这十来个人做了3个月的系统杀掉了。
        这个让我非常沮丧,最痛苦的是下线之后另一拨卖家不满了,说这么好的功能怎么没有了?这个产品带给我们的是新技术(AJAXprototype框架)的尝试,以及新技术对用户操作习惯的改变,一定要慎之又慎。另外还有一点没有总结好的教训就是应对群体事件时,我们手足无措,在后来的“招财进宝”和淘宝商城出现群体性事件的时候悲剧再次重演。

3.招财进宝

        这个是最悲剧的产品。在2006年“五一”的时候,一个划时代的项目启动了。财神说要用最好的项目阵容,我被选中了,这下让我觉得我能划分到最好的员工之类,在“我的淘宝”这个产品中严重受伤的心又痊愈了。这是一个商品P4P的系统,就是按成交付费。
        我们认为已经有很多卖家有钱了,但淘宝上这么多产品,他们很难被找到,卖家愿意花钱让商品排在前面。我们允许卖家购买广告位,把他的商品按一定算法给出排名(类似于百度的竞价排名,但不仅仅看他出了多少钱,还要看信用、成交量、被收藏数量等,这个算法弄得很复杂)。
        这个系统进行得很顺利,但发布的时候,更大的群体性事件出来了,买家们质疑:你们不是承诺三年不收费吗?收广告费不是收费吗?后来我们的竞争对手又推波助澜,公关公司和圈子里各路大侠上蹿下跳,甚至同行推出“一键搬家”的功能来收纳我们的会员。为了收场,我们又一次在论坛上让用户投票决定产品是否下线,同“我的淘宝”一样,以悲剧收场。同样另一拨卖家会说“这么好的功能怎么没有了?”直到Yahoo中国合并后,开发了淘宝直通车,才以类似的产品形态满足了这部分需求。
        虽然“招财进宝”失败了,但这个项目中队技术的探索更加深入,其中用到了用户行为追踪、AJAX。而且有一个技术的细节非常经典,淘宝商品详情页面每天的流量有几个亿,里面的内容都是放在缓存里的,做“招财进宝”时要给卖家显示他们商品被浏览的次数,如下图所示。

        这个数字必须实时更新,而用缓存一般都是异步更新的,所以一开始根本没考虑把这个数据放入缓存里。我们在商品表里添加了这样一个字段,每增加一个PV,该字段就要更新一次。发布一个小时后,数据库就挂掉了。数据库撑不住怎么办?一般的缓存策略是不支持实时更新的,这时候多隆大神向量个办法(不错,又是他!),在Pache上面写了一个模块,这个数字根本不经过下层的WebApp容器(只经过Apache)就写入一个集中式的缓存区了,这个缓存区的数据再异步更新到数据库。这就是我们前面提到的,整个商品详情的页面都在缓存中了,把缓存用到了极致。
        接下来,我们就说说缓存的技术把!
        PS: 感觉写过博客的人对这些浏览量数字应该有些敏感吧!不知道CSDN是否能实现自动推送优秀博客的功能,可以结合多个方面进行推送到首页或左栏。同时由于 没有接触实际项目时,我真的不知道缓存如何来应用,它的好处如何体现,内存、硬盘、缓存这些知识如何在真实的项目中去应用呢?大家可以思考下。

三. Tair

        淘宝在很早就开始使用缓存技术了,在2004年的时候,我们使用一个叫做ESI(Edge Side Includes)的缓存(Cache)。在决定采用ESI之前,多隆试用了Java很多Cache,但都比较重,后来用了Oracle WebCache,也经常挂掉,Oracle Web Cache也支持ESI,多隆由此发现了ESI这个好东西。
        ESI是一种数据缓冲/缓存服务器,它提供将Web网页的部分(这里指页面的片段)进行缓冲/缓存的技术及服务。以往的数据缓冲服务器和信息传送服务以“页”为单位,复制到数据缓冲服务器中,这用于处理静态页面很有效,但在面对动态内容时,就很难得到高效率。在ESI中是部分的缓冲网页,使用基于XML的标记语言,指定想要缓冲的页面部分。
        由此,页面内分为动态地变更部分和静态的不变更部分,只将静态的部分有效地发送到服务器中。淘宝网的数据虽然大部分是动态产生的,但页面中的静态片段也有很多,例如页面的头尾,商品详情页面的卖家信息登,如下图右侧,这些最早都是从ESI缓存中读取的。


        ESI解决了页面静态片段的缓存,聪明的读者可能会想到在后端的那些数据能不能使用缓存?显然也是可以的,而且是必须的。如一个大卖家的商品一天的浏览量可能是几百万,而一个小卖家可能只有几个,那么这个大卖家的用户信息要是每次都从数据库中读取,显然不划算,要是把这个信息放在内存中,每次都从内存里取,性能要好很多。
        这种应用场景就是memcached这种Key-Value缓存的用武之地。只可惜,在淘宝急需memcached时,它还没有崭露头角。我们的架构师多隆大神再一次出手写了一个缓存系统,叫TBstore,这是一个分布式基于Berkeley DB的缓存系统。推出之后,阿里巴巴内部使用非常广泛,尤其对于淘宝,TBstore上应用了ESI、Checkcode(验证码)、Description(商品详情)、Story(心情故事,商品信息里面的一个大字段,长度仅次于商品详情)、用户信息登内容。
        TBstore的分布式算法实现:根据保存的Key(关键字),对Key进行Hash算法,取得Hash值,再对Hash值与总Cache服务器数据取模。然后根据取模后的值,找到服务器列表中下标为此值的Cache服务器。由Java Client API封装实现,应用无须关心。
        TBstore有一个优点,这也是它的弱点,它的存储是基于Berkeley DB的,而Berkeley DB在数据量超过内存时,就要往磁盘上写数据了,所以它是可以做持久化存储的。但是一旦往磁盘写入数据,作为缓存的性能就大幅下降。
        这时有一个项目推动了淘宝在缓存方面的技术提升。在2007年,我们把淘宝的用户信息独立出来,形成一个中心系统UIC(User Information Center),因为淘宝所有的功能都要依赖于用户信息,所以这个模块必须单独拿出来,否则以后的系统无法扩展。把UIC拿出来后,应用系统访问UIC,UIC访问数据库取得用户信息,每天要取几十亿条的用户信息,若直接查询数据库,数据库肯定会崩溃,这必须要用缓存。于是多隆专门为UIC写了一个缓存系统,数据全部存放在内存中。
         到2009年,多隆又参考了memcached的内存结构,改进了TDBM的集群分布方式,在内存利用率和吞吐量方面做了大幅提升,退出了TDBM 2.0系统。
        由于TDBMTBstore的数据接口和用途都很相似,开发团队把二者合并,推出了淘宝自创的Key-Value缓存系统——TairTaoBao Pair的意思,PairKey-Value数据对)。
        Tair包括缓存和持久化两种存储功能。Tair作为一个分布式系统,由一个中心控制节点和一系列的服务节点组成,我们称中心控制节点为Config Server,维护Data Server的状态信息。Data Server对外提供各种数据服务,并以心跳的形式将自身的状况汇报给Config Server。Config Server是控制点,而且是单点,目前采用一主一备的形式来保存其可靠性。所有的Data Server地位都是等价的,Tair的架构如下图所示:


        系统部署结构如下图所示:

        目前,Tair支撑了淘宝几乎所有系统的缓存信息。Tair已开源,地址为code.taobao.org。在创造了TFS和Tair之后,整个系统的架构如下图所示:

        在这个时候,研发部对搜索引擎iSearch也进行了一次升级,之前的搜索引擎是把数据分到多台机器上,但是每份数据只有一份,现在是每份数据变成多份,整个系统从一个单行的部署变成了矩阵,能够支撑更大的访问量,并且做到很高的可用性。到2007年,淘宝网的日均PV达到2.5亿个,商品数超过1亿个,注册会员数达5千多万个,全网成交额达433亿元。
        后面的文章将讲述分布式时代、中间件、Session框架、开放平台等内容。希望文章对大家有所帮助,如果有不足之处,还请海涵~希望大家有个愉快的五一假期!
      (By:Eastmount 2015-5-1 晚上7点   http://blog.csdn.net/eastmount/



你可能感兴趣的:(读书笔记,读书笔记,淘宝技术,TFS,Tair,海量图片处理)