淘寶創(chuàng)造:創(chuàng)新起始的巨人
淘寶的緩存技術(shù)
淘寶在很早就開(kāi)始使用緩存技術(shù)了,在2004年的時(shí)候,我們使用一個(gè)叫做ESI(Edge Side Includes)的緩存(Cache)。在決定采用ESI之前,多隆試用了Java的很多Cache,但都比較重,后來(lái)用了Oracle Web Cache,也經(jīng)常掛掉,Oracle Web Cache也支持ESI,多隆由此發(fā)現(xiàn)了ESI這個(gè)好東東。ESI是一種數(shù)據(jù)緩沖/緩存服務(wù)器,它提供將Web網(wǎng)頁(yè)的部分(這里指頁(yè)面的片段)進(jìn)行緩沖/緩沖的技術(shù)及服務(wù)。以往的數(shù)據(jù)緩沖服務(wù)器和信息傳送服務(wù)器以“頁(yè)”為制作單位,復(fù)制到數(shù)據(jù)緩沖服務(wù)器中,這用于處理靜態(tài)頁(yè)面很有效,但在面對(duì) 動(dòng)態(tài)內(nèi)容的時(shí)候,就很難得到高效率。在ESI中是部分的緩沖網(wǎng)頁(yè),使用基于XML的標(biāo)記語(yǔ)言,指定逍遙緩沖的頁(yè)面部分。由此,頁(yè)面內(nèi)分為動(dòng)態(tài)地變更部分和靜態(tài)的不變部分,只將靜態(tài)的部分有效地發(fā)送到服務(wù)器中。淘寶網(wǎng)的數(shù)據(jù)雖然是動(dòng)態(tài)產(chǎn)生的,但頁(yè)面中的靜態(tài)片段也有很多,例如頁(yè)面的投、尾,商品詳情頁(yè)面的賣(mài)家信息等們這些都是從ESI緩存中讀取的。
回顧一下上面幾個(gè)版本,1.0版的PHP系統(tǒng)運(yùn)行了將近一年的時(shí)間(2003年5月—2004年1月),服務(wù)器由一臺(tái)發(fā)展到多臺(tái);后來(lái)數(shù)據(jù)庫(kù)撐不住了,將MySQL換成了Oracle,引入了搜索引擎
(2004年1月—2004年5月,叫1.1版本);然后不到半年的時(shí)間又把開(kāi)發(fā)語(yǔ)言換成了Java(2004年2月—2005年3月,叫2.0版本),數(shù)據(jù)服務(wù)逐步采用了IOE;隨著數(shù)據(jù)量和訪問(wèn)量的增長(zhǎng),我們進(jìn)行數(shù)據(jù)分庫(kù)、加入緩存、使用CDN(2004年10月—2007年1月,叫2.1版本)。這幾個(gè)版本中間有些時(shí)間上的重合,因?yàn)楹芏嗉軜?gòu)的演化并沒(méi)有明顯的時(shí)間點(diǎn),它是逐步進(jìn)化而來(lái)的。
在描述2.1版本的時(shí)候,我寫(xiě)的標(biāo)題是《堅(jiān)若磐石》,這個(gè)“堅(jiān)若磐石”是因?yàn)檫@個(gè)版本終于穩(wěn)定下來(lái)了,在這個(gè)版本的系統(tǒng)上,淘寶網(wǎng)運(yùn)行了兩年多的時(shí)間。這期間有很多優(yōu)秀的人才加入,也開(kāi)發(fā)了很多優(yōu)秀的產(chǎn)品,例如,商品的類(lèi)目屬性、支付寶認(rèn)證系統(tǒng)、招財(cái)進(jìn)寶項(xiàng)目、淘寶旅行、淘寶彩票、淘寶論壇等,甚至在團(tuán)購(gòu)網(wǎng)站風(fēng)起云涌之前,淘寶網(wǎng)在2006年就推出了“團(tuán)購(gòu)”的功能。
在這些產(chǎn)品和功能的最底層,其實(shí)還是商品管理和交易管理這兩大功能。這兩大功能在2.1版本中都有很大的變化。商品管理起初是要求賣(mài)家選擇7天到期還是14天到期,到期之后自動(dòng)下架,必須重新發(fā)布才能上架,上架之后就變成了新的商品信息(ID變過(guò)了)。另外,如果商品在這期間成交了,之后再有新貨,必須發(fā)布一個(gè)新的商品信息。這么做有幾個(gè)原因,一是參照拍賣(mài)商品的時(shí)間設(shè)置,要在某日期前結(jié)束掛牌;二是搜索引擎不知道同樣的商品哪個(gè)排在前面,那就把掛牌時(shí)間長(zhǎng)的排前面(這樣就必須在某個(gè)時(shí)間把老的商品下架,否則它會(huì)一直排在前面);第三是成交信息和商品ID關(guān)聯(lián),這個(gè)商品如果多次編輯還是同一個(gè)ID的話(huà),成交記錄中的商品信息會(huì)不斷改變;還有一個(gè)不為人知的原因是我們的存儲(chǔ)有限,不能讓所有的商品老存放在主庫(kù)中。這種處理方式簡(jiǎn)單粗暴,但還算是公平。不過(guò)這樣會(huì)導(dǎo)致很多需求都無(wú)法滿(mǎn)足,例如,賣(mài)出一件商品之后就無(wú)法更改價(jià)格,否則前面已經(jīng)成交的那個(gè)價(jià)格都變了,而且同樣的商品,上一次銷(xiāo)售后的很多好評(píng)都無(wú)法在下一個(gè)商品上體現(xiàn)出來(lái);再如,我買(mǎi)過(guò)的商品結(jié)束后只看到交易的信息,不知道賣(mài)家是否還會(huì)賣(mài)?;谶@些需求,我們?cè)?006年下半年把商品和交易拆開(kāi),一個(gè)商家的一種商品有一個(gè)唯一的ID,上下架都是同一個(gè)商品。那么如果賣(mài)家修改價(jià)格和庫(kù)存等信息,已成交的信息怎么處理?那就在買(mǎi)家每交易一次的時(shí)候,都記錄下商品的快照信息,有多少次交易就有多少個(gè)快照。這樣買(mǎi)賣(mài)雙方比較爽了,但這給系統(tǒng)帶來(lái)了什么?存儲(chǔ)的成本大幅度上升了!
淘寶文件系統(tǒng)——TFS
存儲(chǔ)的成本高到什么程度呢?數(shù)據(jù)庫(kù)方面用了IOE,一套下來(lái)就是千萬(wàn)級(jí)別的,那幾套下來(lái)就是——好多錢(qián)啊。另外,淘寶網(wǎng)還有很多文件需要存儲(chǔ),最主要的就是圖片、商品描述、交易快照,一個(gè)商品要包含幾張圖片和一長(zhǎng)串的描述信息,而每一張圖片都要生成幾張規(guī)格不同的縮略圖。在2010年,淘寶網(wǎng)的后端系統(tǒng)上保存著286億個(gè)圖片文件。圖片在交易系統(tǒng)中非常重要,大家常說(shuō)“一張好圖勝千言”、“無(wú)圖無(wú)真相”,淘寶網(wǎng)的商品照片,尤其是熱門(mén)商品圖片的訪問(wèn)流量是非常大的。在淘寶網(wǎng)整體流量中,圖片的訪問(wèn)流量要占到90%以上,而且這些圖片平均大小為17.45KB,小于8KB的圖片占整體圖片數(shù)量的61%,占整體系統(tǒng)容量的11%。這么多的圖片數(shù)據(jù)、這么大的訪問(wèn)流量,給淘寶網(wǎng)的系統(tǒng)帶來(lái)了巨大的挑戰(zhàn)。對(duì)于大多數(shù)系統(tǒng)來(lái)說(shuō),最頭疼的就是大規(guī)模的小文件存儲(chǔ)與讀取,因?yàn)榇蓬^需要頻繁尋道和換道,因此,在讀取上容易帶來(lái)較長(zhǎng)的延時(shí)。在大量高并發(fā)訪問(wèn)量的情況下,簡(jiǎn)直就是系統(tǒng)的噩夢(mèng)。我們?cè)撛趺崔k?
同樣的套路,在某個(gè)規(guī)模以下采用現(xiàn)有的商業(yè)解決方案,達(dá)到某種規(guī)模之后,商業(yè)的解決方案無(wú)法滿(mǎn)足,只有自己創(chuàng)造解決方案了。對(duì)于淘寶的圖片存儲(chǔ)來(lái)說(shuō),轉(zhuǎn)折點(diǎn)在2007年。這之前,一直采用商用存儲(chǔ)系統(tǒng),應(yīng)用NetApp公司的文件存儲(chǔ)系統(tǒng)隨著淘寶網(wǎng)的圖片文件數(shù)量以每年3倍的速度增長(zhǎng),淘寶網(wǎng)后端NetApp公司的存儲(chǔ)系統(tǒng)也從低端到高端不斷遷移,直至2006年,即使是NetApp公司最高端的產(chǎn)品也不能滿(mǎn)足淘寶網(wǎng)存儲(chǔ)的要求。從2006年開(kāi)始,我們決定自己開(kāi)發(fā)一套針對(duì)海量小文件存儲(chǔ)的文件系統(tǒng),用于解決自身圖片存儲(chǔ)的難題。這標(biāo)志著淘寶網(wǎng)從使用技術(shù)到了創(chuàng)造技術(shù)的階段。
2007年之前的圖片存儲(chǔ)架構(gòu)如下圖所示。
在一次架構(gòu)師大會(huì)上,章文嵩博士總結(jié)了幾點(diǎn)商用存儲(chǔ)系統(tǒng)的局限和不足。
第一,商用存儲(chǔ)系統(tǒng)沒(méi)有對(duì)小文件存儲(chǔ)和讀取的環(huán)境進(jìn)行有針對(duì)性的優(yōu)化;第二,文件數(shù)量大,網(wǎng)絡(luò)存儲(chǔ)設(shè)備無(wú)法支撐;第三,整個(gè)系統(tǒng)所連接的服務(wù)器越來(lái)越多,網(wǎng)絡(luò)連接數(shù)已經(jīng)達(dá)到網(wǎng)絡(luò)存儲(chǔ)設(shè)備的極限;第四,商用存儲(chǔ)系統(tǒng)擴(kuò)容成本高,10TB的存儲(chǔ)容量需要幾百萬(wàn)元,而且存在單點(diǎn)故障,容災(zāi)和安全性無(wú)法得到很好的保證。
談到在商用系統(tǒng)和自主研發(fā)之間的經(jīng)濟(jì)效益方面的對(duì)比,章文嵩博士列舉了以下幾點(diǎn)經(jīng)驗(yàn)。
第一,商用軟件很難滿(mǎn)足大規(guī)模系統(tǒng)的應(yīng)用需求,無(wú)論是存儲(chǔ)、CDN還是負(fù)載均衡,在廠商實(shí)驗(yàn)室端,都很難實(shí)現(xiàn)如此大的數(shù)據(jù)規(guī)模測(cè)試。
第二,在研發(fā)過(guò)程中,將開(kāi)源和自主開(kāi)發(fā)相結(jié)合,會(huì)有更好的可控性,若系統(tǒng)出了問(wèn)題,完全可以從底層解決問(wèn)題,系統(tǒng)擴(kuò)展性也更高。
第三, 在一定規(guī)模效應(yīng)的基礎(chǔ)上,研發(fā)的投入都是值得的。下圖演示的是一個(gè)自主研發(fā)和購(gòu)買(mǎi)商用系統(tǒng)的投入產(chǎn)出比,實(shí)際上,圖中交叉點(diǎn)的左邊,購(gòu)買(mǎi)商用系統(tǒng)都是更加實(shí)際和經(jīng)濟(jì)性更好的選擇,只有在規(guī)模超過(guò)交叉點(diǎn)的情況下,自主研發(fā)才能收到較好的經(jīng)濟(jì)效果。實(shí)際上,規(guī)?;_(dá)到如此程度的公司并不多,不過(guò)淘寶網(wǎng)已經(jīng)遠(yuǎn)遠(yuǎn)超過(guò)了交叉點(diǎn)。
第四,自主研發(fā)的系統(tǒng)可在軟件和硬件的多個(gè)層次之間不斷優(yōu)化。
#p#
歷史總是驚人的巧合,在我們準(zhǔn)備研發(fā)文件存儲(chǔ)系統(tǒng)的時(shí)候,Google走在了前面,2007年,他們公布了GFS(Google FileSystem)的設(shè)計(jì)論文,這給我們帶來(lái)了很多借鑒的思路。隨后我們開(kāi)發(fā)出了適合淘寶使用的圖片存儲(chǔ)系統(tǒng)(TaoBao File System,TFS)。3年之后,我們發(fā)現(xiàn)歷史的巧合比我們想象的還要神奇,幾乎跟我們同時(shí),中國(guó)的另外一家互聯(lián)網(wǎng)公司也開(kāi)發(fā)了他們的文件存儲(chǔ)系統(tǒng),甚至取的名字都一樣——TFS,太神奇了?。ú虏率悄募遥?/p>
2007年6月,TFS正式上線(xiàn)運(yùn)營(yíng)。在生產(chǎn)環(huán)境中應(yīng)用的集群規(guī)模達(dá)到了200臺(tái)PC Server(146GB×6 SAS 15KB Raid5),文件數(shù)量達(dá)到上億級(jí)別;系統(tǒng)部署存儲(chǔ)容量為140TB;實(shí)際使用存儲(chǔ)容量為50TB;單臺(tái)支持隨機(jī)IOPS 200+,流量為3MB/s。
說(shuō)到TFS的系統(tǒng)架構(gòu),首先要描述清楚業(yè)務(wù)需求,淘寶對(duì)圖片存儲(chǔ)的需求大概可以描述如下:文件比較?。徊l(fā)量高;讀操作遠(yuǎn)大于寫(xiě)操作;訪問(wèn)隨機(jī);沒(méi)有文件修改的操作;要求存儲(chǔ)成本低;能容災(zāi),能備份。顯然,應(yīng)對(duì)這種需求時(shí)要用分布式存儲(chǔ)系統(tǒng);由于文件大小比較統(tǒng)一,可以采用專(zhuān)有文件系統(tǒng);由于并發(fā)量高,讀寫(xiě)隨機(jī)性強(qiáng),需要更少的I/O操作;考慮到成本和備份,需要用廉價(jià)的存儲(chǔ)設(shè)備;考慮到容災(zāi),需要能平滑擴(kuò)容。
參照GFS并做了大量的優(yōu)化之后,TFS 1.0版的架構(gòu)圖如下。
從上面的架構(gòu)圖可看出:集群由一對(duì)Name Server和多臺(tái)DataServer構(gòu)成,Name Server的兩臺(tái)服務(wù)器互為雙機(jī),這就是集群文件系統(tǒng)中管理節(jié)點(diǎn)的概念。
在這個(gè)系統(tǒng)中:
- 每個(gè)Data Server運(yùn)行在一臺(tái)普通的Linux主機(jī)上;
- 以Block文件的形式存放數(shù)據(jù)文件(一個(gè)Block的大小一般為Block存儲(chǔ)多份是為了保證數(shù)據(jù)安全;
- 利用ext3文件系統(tǒng)存放數(shù)據(jù)文件;
- 磁盤(pán)raid5做數(shù)據(jù)冗余;
- 文件名內(nèi)置元數(shù)據(jù)信息,用戶(hù)自己保存TFS文件名與實(shí)際文件的對(duì)照關(guān)系,這使得元數(shù)據(jù)量特別小。
淘寶TFS文件系統(tǒng)在核心設(shè)計(jì)上最大的取巧在于,傳統(tǒng)的集群系統(tǒng)中元數(shù)據(jù)只有1份,通常由管理節(jié)點(diǎn)來(lái)管理,因而很容易成為瓶頸。而對(duì)于淘寶網(wǎng)的用戶(hù)來(lái)說(shuō),圖片文件究竟用什么名字來(lái)保存他們并不關(guān)心,因此,TFS在設(shè)計(jì)規(guī)劃上考慮在圖片的保存文件名上暗藏了 一些元數(shù)據(jù)信息,例如,圖片的大小、時(shí)間、訪問(wèn)頻次等信息,包括所在的邏輯塊號(hào)。而在實(shí)際的元數(shù)據(jù)上,保存的信息很少,因此,元數(shù)據(jù)結(jié)構(gòu)非常簡(jiǎn)單。僅僅只需要一個(gè)FileID就能夠準(zhǔn)確定位文件在什么地方。由于大量的文件信息都隱藏在文件名中,整個(gè)系統(tǒng)完全拋棄了傳統(tǒng)的目錄樹(shù)結(jié)構(gòu),因?yàn)槟夸洏?shù)開(kāi)銷(xiāo)最大。拿掉后,整個(gè)集群的高可擴(kuò)展性可極大地提高。實(shí)際上,這一設(shè)計(jì)理念和目前業(yè)界的“對(duì)象存儲(chǔ)”較類(lèi)似。
在TFS上線(xiàn)之前,淘寶網(wǎng)每個(gè)商品只允許上傳一張圖片,大小限定在120KB之內(nèi),在商品詳情中的圖片必須使用外站的服淘寶技術(shù)這十年務(wù)。那時(shí)候發(fā)布一件商品確實(shí)非常麻煩,筆者曾經(jīng)想賣(mài)一臺(tái)二手電腦,我先把照片上傳到Google相冊(cè),在發(fā)布到淘寶網(wǎng)之后發(fā)現(xiàn)Google相冊(cè)被墻(即被屏撇,無(wú)法訪問(wèn)),我的圖片別人看不到,當(dāng)時(shí)很郁悶。在TFS上線(xiàn)后,商品展示圖片開(kāi)放到5張,商品描述里面的圖片也可以使用淘寶的圖片服務(wù),到現(xiàn)在為止,淘寶網(wǎng)給每個(gè)用戶(hù)提供了1GB的圖片空間。技術(shù)和業(yè)務(wù)就是這么互相借力推動(dòng)著的,業(yè)務(wù)滿(mǎn)足不了的時(shí)候,技術(shù)必須創(chuàng)新,技術(shù)創(chuàng)新之后,業(yè)務(wù)有了更大的發(fā)展空間。
TFS發(fā)布之后,又經(jīng)歷了多個(gè)版本的修改,到1.3版的時(shí)候已經(jīng)比較成熟了。2009年6月,TFS 1.3版本上線(xiàn),集群規(guī)模大大擴(kuò)展,部署到淘寶的圖片生產(chǎn)系統(tǒng)上,整個(gè)系統(tǒng)已經(jīng)從原有200臺(tái)PC服務(wù)器擴(kuò)增至440臺(tái)PC服務(wù)器(300B×12 SAS 15KB RPM)+30臺(tái)PC服務(wù)器(600B×12 SAS 15KB RPM )。支持文件數(shù)量也擴(kuò)容至百億級(jí)別;系統(tǒng)部署存儲(chǔ)容量為1800TB;當(dāng)前實(shí)際存儲(chǔ)容量為995TB;單臺(tái)DataServer支持隨機(jī)IOPS900+,流量為15MB+;目前NameServer運(yùn)行的物理內(nèi)存是217MB(服務(wù)器使用千兆網(wǎng)卡)。
TFS 1.3版本邏輯結(jié)構(gòu)圖如下圖所示。
在TFS 1.3版本中,工程師們重點(diǎn)改善了心跳和同步的性能,最新版本的心跳和同步在幾秒鐘之內(nèi)就可完成切換,同時(shí)進(jìn)行了一些新的優(yōu)化,包括元數(shù)據(jù)存儲(chǔ)在內(nèi)存中、清理磁盤(pán)空間等。
性能上也做了優(yōu)化,包括如下內(nèi)容。
- 采用ext4文件系統(tǒng),并且預(yù)分配文件,減少ext3等文件系統(tǒng)淘寶技術(shù)這十年數(shù)據(jù)碎片帶來(lái)的性能損耗;
- 單進(jìn)程管理單塊磁盤(pán)的方式,摒除RAID5機(jī)制;
- 帶有HA機(jī)制的中央控制節(jié)點(diǎn),在安全穩(wěn)定和性能復(fù)雜度之間取得平衡;
- 縮減元數(shù)據(jù)大小,將更多的元數(shù)據(jù)加載入內(nèi)存,提升訪問(wèn)速度;
- 跨機(jī)架和IDC的負(fù)載均衡及冗余安全策略;
- 完全平滑擴(kuò)容。
對(duì)于整個(gè)圖片服務(wù)來(lái)說(shuō),僅有TFS還是不夠的,整個(gè)圖片服務(wù)機(jī)器的拓?fù)浣Y(jié)構(gòu)如下圖所示。
整個(gè)圖片存儲(chǔ)系統(tǒng)就像一個(gè)龐大的服務(wù)器,有處理單元、緩存單元和存儲(chǔ)單元。前面已經(jīng)介紹過(guò)后臺(tái)的TFS集群文件存儲(chǔ)系統(tǒng),在TFS前端,還部署著200多臺(tái)圖片文件服務(wù)器,Apache實(shí)現(xiàn),用于生成縮略圖的運(yùn)算。
值得一提的是,根據(jù)淘寶網(wǎng)的縮略圖生成規(guī)則,縮略圖都是實(shí)時(shí)生成的。這樣做的好處有兩點(diǎn):一是為了避免后端圖片服務(wù)器上存儲(chǔ)的圖片數(shù)量過(guò)多,大大節(jié)約后臺(tái)存儲(chǔ)空間的需求,我們計(jì)算過(guò),采用實(shí)時(shí)生成縮略圖的模式比提前全部生成好縮略圖的模式節(jié)約90%的存儲(chǔ)空間。也就是說(shuō),存儲(chǔ)空間只需要后一種模式的10%。二是,縮略圖可根據(jù)需要實(shí)時(shí)生成,這樣更加靈活。
圖片文件服務(wù)器的前端則是一級(jí)緩存和二級(jí)緩存,前面還有全局負(fù)載均衡的設(shè)置,用于解決圖片的訪問(wèn)熱點(diǎn)問(wèn)題。圖片的訪問(wèn)熱點(diǎn)一定存在,重要的是,讓圖片盡量在緩存中命中。目前淘寶網(wǎng)在各個(gè)運(yùn)營(yíng)商的中心點(diǎn)設(shè)有二級(jí)緩存,整體系統(tǒng)中心店設(shè)有一級(jí)緩存,加上全局負(fù)載均衡,傳遞到后端TFS的流量就已經(jīng)非常均衡和分散了,對(duì)前端的響應(yīng)性能也大大提高。據(jù)淘寶的緩存策略,大部分圖片都盡量在緩存中命中,如果緩存中無(wú)法命中,則會(huì)在本地服務(wù)器上查找是否存有原圖,并根據(jù)原圖生成縮略圖,如果都沒(méi)有命中,則會(huì)考慮去后臺(tái)TFS集群文件存儲(chǔ)系統(tǒng)上調(diào)取。因此,最終反饋到TFS集群文件存儲(chǔ)系統(tǒng)上的流量已經(jīng)被大大優(yōu)化了。
淘寶網(wǎng)將圖片處理與緩存編寫(xiě)成基于Nginx的模塊,我們認(rèn)為,Nginx是目前性能最高的HTTP服務(wù)器,代碼清晰,模塊化非常好。淘寶網(wǎng)使用GraphicsMagick進(jìn)行圖片處理,采用了面向小對(duì)象的緩存文件系統(tǒng),前端有LVS+Haproxy將原圖和其所有的縮略圖請(qǐng)求都調(diào)度到同一臺(tái)Image Server(圖片服務(wù)器)。
在文件定位上,內(nèi)存用Hash算法做索引,最多一次讀盤(pán)。另外會(huì)有很多相同的圖片重復(fù)上傳上來(lái),去除重復(fù)文件也是采用Hash算法來(lái)做的。寫(xiě)盤(pán)方式則采用Append方式寫(xiě),并采用了淘汰策略FIFO,主要考慮降低硬盤(pán)的寫(xiě)操作,沒(méi)有必要進(jìn)一步提高Cache命中率,因?yàn)镮mageServer和TFS位于同一個(gè)數(shù)據(jù)中心,讀盤(pán)效率還是非常高的。目前淘寶網(wǎng)的TFS已經(jīng)開(kāi)源(見(jiàn)code.taobao.org),業(yè)界的同仁可以一起使用和完善這個(gè)系統(tǒng)。