互聯(lián)網(wǎng)應(yīng)用經(jīng)常需要存儲用戶上傳的文檔奢人、圖片谓媒、視頻等,比如Facebook相冊何乎、淘寶圖片句惯、Dropbox文檔等土辩。文檔、圖片抢野、視頻一般稱為Blob數(shù)據(jù)拷淘,存儲Blob數(shù)據(jù)的文件系統(tǒng)也相應(yīng)地稱為Blob存儲系統(tǒng)。每個Blob數(shù)據(jù)一般都比較大指孤,而且多個Blob之間沒有關(guān)聯(lián)启涯。Blob文件系統(tǒng)的特點是數(shù)據(jù)寫入后基本都是只讀,很少出現(xiàn)更新操作恃轩。這兩節(jié)分別以Taobao File System和Facebook Haystack為例說明Blob文件系統(tǒng)的架構(gòu)结洼。
2007年以前淘寶的圖片存儲系統(tǒng)使用了昂貴的NetApp存儲設(shè)備,由于淘寶數(shù)據(jù)量大且增長很快叉跛,出于性能和成本的考慮松忍,淘寶自主研發(fā)了Blob存儲系統(tǒng)Tabao File System(TFS)。目前筷厘,TFS中存儲的圖片規(guī)模已經(jīng)達到百億級別鸣峭。
TFS架構(gòu)設(shè)計時需要考慮如下兩個問題:
Metadata信息存儲。由于圖片數(shù)量巨大敞掘,單機存放不了所有的元數(shù)據(jù)信息叽掘,假設(shè)每個圖片文件的元數(shù)據(jù)占用100字節(jié),100億圖片的元數(shù)據(jù)占用的空間為10G×0.1KB=1TB玖雁,單臺機器無法提供元數(shù)據(jù)服務(wù)。
減少圖片讀取的IO次數(shù)盖腕。在普通的Linux文件系統(tǒng)中赫冬,讀取一個文件包括三次磁盤IO:首先讀取目錄元數(shù)據(jù)到內(nèi)存,其次把文件的inode節(jié)點裝載到內(nèi)存溃列,最后讀取實際的文件內(nèi)容劲厌。由于小文件個數(shù)太多,無法將所有目錄及文件的inode信息緩存到內(nèi)存听隐,因此磁盤IO次數(shù)很難達到每個圖片讀取只需要一次磁盤IO的理想狀態(tài)补鼻。
因此,TFS設(shè)計時采用的思路是:多個邏輯圖片文件共享一個物理文件雅任。
系統(tǒng)架構(gòu)
TFS架構(gòu)上借鑒了GFS风范,但與GFS又有很大的不同。首先沪么,TFS內(nèi)部不維護文件目錄樹硼婿,每個小文件使用一個64位的編號表示;其次禽车,TFS是一個讀多寫少的應(yīng)用寇漫,相比GFS,TFS的寫流程可以做得更加簡單有效刊殉。
如圖4-4所示,一個TFS集群由兩個NameServer節(jié)點(一主一備)和多個DataServer節(jié)點組成州胳,NameServer通過心跳對DataSrver的狀態(tài)進行監(jiān)測记焊。NameServer相當(dāng)于GFS中的Master,DataServer相當(dāng)于GFS中的ChunkServer。NameServer區(qū)分為主NameServer和備NameServer栓撞,只有主NameServer提供服務(wù)亚亲,當(dāng)主NameServer出現(xiàn)故障時,能夠被心跳守護進程檢測到腐缤,并將服務(wù)切換到備NameServer捌归。每個DataServer上會運行多個dsp進程,一個dsp對應(yīng)一個掛載點岭粤,這個掛載點一般對應(yīng)一個獨立磁盤惜索,從而管理多塊磁盤。
在TFS中剃浇,將大量的小文件(實際數(shù)據(jù)文件)合并成一個大文件巾兆,這個大文件稱為塊(Block),每個Block擁有在集群內(nèi)唯一的編號(塊ID)虎囚,通過<塊ID角塑,塊內(nèi)偏移>可以唯一確定一個文件。TFS中Block的實際數(shù)據(jù)都存儲在DataServer中淘讥,大小一般為64MB圃伶,默認(rèn)存儲三份,相當(dāng)于GFS中的chunk蒲列。應(yīng)用客戶端是TFS提供給應(yīng)用程序的訪問接口窒朋,應(yīng)用客戶端不緩存文件數(shù)據(jù),只緩存NameServer的元數(shù)據(jù)蝗岖。
1.追加流程
TFS中的追加流程相比GFS要簡單有效很多侥猩。GFS中為了減少對Master的壓力,引入了租約機制抵赢,從而將修改權(quán)限下放到主ChunkServer欺劳,很多追加操作都不需要Master參與。然而铅鲤,TFS是寫少讀多的應(yīng)用划提,即使每次寫操作都需要經(jīng)過NameNode也不會出現(xiàn)問題,大大簡化了系統(tǒng)的設(shè)計彩匕。另外腔剂,TFS中也不需要支持類似GFS的多客戶端并發(fā)追加操作,同一時刻每個Block只能有一個寫操作驼仪,多個客戶端的寫操作會被串行化掸犬。
如圖4-5所示袜漩,客戶端首先向NameServer發(fā)起寫請求,NameServer需要根據(jù)DataServer上的可寫塊湾碎、容量和負(fù)載加權(quán)平均來選擇一個可寫的Block宙攻,并且在該Block所在的多個DataServer中選擇一個作為寫入的主副本(Primary),其他的作為備副本(Secondary)介褥。接著座掘,客戶端向主副本寫入數(shù)據(jù),主副本將數(shù)據(jù)同步到多個備副本柔滔。如果所有的副本都修改成功溢陪,主副本會首先通知NameServer更新Block的版本號,成功以后才會返回客戶端操作結(jié)果睛廊。如果中間發(fā)生任何錯誤形真,客戶端都可以從第一步開始重試。相比GFS,TFS的寫流程不夠優(yōu)化超全,第一咆霜,每個寫請求都需要多次訪問NameServer;第二嘶朱,數(shù)據(jù)推送也沒有采用流水線方式減小延遲蛾坯。淘寶的系統(tǒng)是需求驅(qū)動的,用最簡單的方式解決用戶面臨的問題疏遏。
每個寫操作返回后脉课,會返回客戶端兩個信息,小文件在TFS中的Block編號(Block id)以及Block偏移(Block offset)改览。應(yīng)用系統(tǒng)會將這些信息保存到數(shù)據(jù)庫中下翎,圖片讀取的時候首先根據(jù)Block編號從NameServer查找Block所在的DataServer,然后根據(jù)Block偏移讀取圖片數(shù)據(jù)宝当。TFS的一致性模型保證所有返回給客戶端的<Blockid,Block offset>標(biāo)識的圖片數(shù)據(jù)在TFS中的所有副本都是有效的。
2.NameServer
NameServer主要功能是:Block管理胆萧,包括創(chuàng)建庆揩、刪除、復(fù)制跌穗、重新均衡订晌;Data-Server管理,包括心跳蚌吸、DataServer加入及退出锈拨;以及管理Block與所在DataServer之間的映射關(guān)系。與GFS Master相比羹唠,TFS NameServer最大的不同就是不需要保存文件目錄樹信息奕枢,也不需要維護文件與Block之間的映射關(guān)系娄昆。
NameServer與DataServer之間保持心跳,如果NameServer發(fā)現(xiàn)某臺DataServer發(fā)生故障缝彬,需要執(zhí)行Block復(fù)制操作萌焰;如果新DataServer加入,NameServer會觸發(fā)Block負(fù)載均衡操作谷浅。和GFS類似扒俯,TFS的負(fù)載均衡需要考慮很多因素,如機架分布一疯、磁盤利用率撼玄、DataServer讀寫負(fù)載等。另外墩邀,新DataServer加入集群時也需要限制同時遷入的Block數(shù)量防止被壓垮掌猛。
NameServer采用了HA結(jié)構(gòu),一主一備磕蒲,主NameServer上的操作會重放至備NameServer留潦。如果主NameServer出現(xiàn)問題,可以實時切換到備NameServer辣往。
討論
圖片應(yīng)用中有幾個問題兔院,第一個問題是圖片去重,第二個問題是圖片更新與刪除站削。
由于用戶可能上傳大量相同的圖片坊萝,因此,圖片上傳到TFS前许起,需要去重十偶。一般在外部維護一套文件級別的去重系統(tǒng)(Dedup),采用MD5或者SHA1等Hash算法為圖片文件計算指紋(FingerPrint)园细。圖片寫入TFS之前首先到去重系統(tǒng)中查找是否存在指紋惦积,如果已經(jīng)存在,基本可以認(rèn)為是重復(fù)圖片猛频;圖片寫入TFS以后也需要將圖片的指紋以及在TFS中的位置信息保存到去重系統(tǒng)中狮崩。去重是一個鍵值存儲系統(tǒng),淘寶內(nèi)部使用5.2節(jié)中的Tair來進行圖片去重鹿寻。
圖片的更新操作是在TFS中寫入新圖片睦柴,并在應(yīng)用系統(tǒng)的數(shù)據(jù)庫中保存新圖片的位置,圖片的刪除操作僅僅在應(yīng)用系統(tǒng)中將圖片刪除毡熏。圖片在TFS中的位置是通過<Block id,Block offset>標(biāo)識的坦敌,且Block偏移是在Block文件中的物理偏移,因此,每個Block中只要還有一個有效的圖片文件就無法回收狱窘,也無法對Block文件進行重整杜顺。如果系統(tǒng)的更新和刪除比較頻繁,需要考慮磁盤空間的回收训柴,這點會在Facebook Haystack系統(tǒng)中具體說明哑舒。